Another idea for record field selection and better namespace management

Hi - To avoid the problems with so many names being put into a module's namespace, data declarations could implicitly define sub-modules and class/instance declarations as follows: module M where data Foo = FooCon {x : Int} would declare (as seen from inside M) Foo, Foo.FooCon, Foo.x and would further declare x and FooCon as instances of a global value type-class and constructor type class as follows (where //varid denotes the global typeclass corresponding to (a record field called) varid, and //conid denotes the global typeclass corresponding to the constructor conid) class //x a b where x : a -> b instance //x Foo Int where x Foo.FooCon{x=p} = p class //FooCon a b where FooCon : a -> b instance //FooCon Int Foo where FooCon = Foo.FooCon The class declarations (generated by the compiler) are global, and there is no danger of conflicts with user class declarations because of the // prefix. The instance declarations (also generated by the compiler) would be inserted into the module itself. This would give at least three advantages: 1) The same names could be used for fields in more than one data declaration and these would be resolved using the well known type class mechanism 2) Some exciting new programming paradigms become instantly available due to the extension of allowing constructor type classes, namely we could then get the effect of extensible data types eg data Col1 a = One a data Col2 a = One a | Two a useOne :: ( //One col a) => col -> a useOne (One x) = x This is a lot more powerful than just OOP, because we could have different views of a data type, selecting out those components which are relevant to particular operations: data Element = TerminalPunct | TerminalValue | NonTerminal | Push | Pop data Action = Push | Pop data Insertion = TerminalValue | NonTerminal | Push without having to artificially construct various injections... 3) If x is a record field, then because a typeclass and instance has been automatically generated, (x p) already uses the type of p to determine which overloaded x to use, so all that remains is to introduce a sugar to get a form of function application syntax that binds stronger than prefix application. I suggest p^x === (x p) It is still possible to be completely explicit, by writing P.x p or p^P.x I think this solves all the problems that I had with the value space idea, and is also a fairly conservative extension to Haskell as it stands at the moment, except I wonder if it is possible to implement type classes for constructors? Regards, Brian.

Apologies - I've noticed some mistakes corrected as follows: Brian Hulley wrote:
class //x a b where x : a -> b
class //FooCon a b where FooCon : a -> b
class //x a b | a -> b where -- I think this fundep is correct x :: a->b -- I can never get used to having to write :: instead of : class //FooCon a b | b -> a where FooCon :: a->b
This is a lot more powerful than just OOP, because we could have different views of a data type, selecting out those components which are relevant to particular operations:
data Element = TerminalPunct | TerminalValue | NonTerminal | Push | Pop data Action = Push | Pop data Insertion = TerminalValue | NonTerminal | Push
without having to artificially construct various injections...
No - these are not in fact views. A view would be given by multiple predicates eg (//Push a,//Pop a) => ... a ... as normal. Regards, Brian.
participants (1)
-
Brian Hulley