[Haskell-cafe] Another idea for record field selection and better namespace management

Brian Hulley brianh at metamilk.com
Fri Jan 27 05:22:33 EST 2006


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.





More information about the Haskell-Cafe mailing list