First class labels
Claus Reinke
claus.reinke at talk21.com
Tue Feb 7 08:06:48 EST 2006
[The reader will have noticed the absence of the words
extensible polymorphic records in the subject line]
If the long-overdue overhaul of Haskell's record system
appears to be out of scope for Haskell' (??), I suggest to add
some form of first-class labels to Haskell' (to be really useful,
this depends on real type classes, not the cut-down version
of Haskell 98).
I often find myself coding up my own records, which is fairly
quick and painless, though of course lacking the comfort of
a real records systems (see code at bottom of this message;
one might add some syntactic sugar, or not).
The two main problems I have with this are
(a) the need for so-called "extensions" (I see these features
merely as removing needless restrictions, and will be
very disappointed if Haskell' does not provide for
them, not even optionally)
(b) the need to declare my labels. it is not so much the
typing, but:
- possible namespace overlaps (someone might
want to use my labels as constructor names)
- the need for a common import origin (someone
has to declare all those labels, and all users
better agree on who that someone is)
This suggestion is concerned with (b). I propose to add
first class labels to Haskell' (every label is a constant, the
only inhabitant of its type). I outline three options, of which
option 1 is my personal favourite, followed by option 3:
Option 1:
remove the need to declare labels, make them identifiable
as such in use. TREX demonstrates that this is possible.
in the past (when I was using Hugs more than GHC), I
have been known to abuse TREX, not for its records,
but for its labels. In other words, I'd use single-field
dummy records "(mylabel=())" as labels in constructions
like the one at the bottom of this message.
pro: simple in use, labels have their own namespace,
no conflicting imports, known to work
con: need to give up some identifiable space in the
language for labels
Option 2:
add sharing imports to the module language. SML
supports something like that, I think.
that would allow importers to declare that the various
imported declarations of a label are not in conflict, but
refer to the very same type.
pro: seems like a useful feature anyway
con: more complex than needed for this proposal,
and would be very verbose in use
Option 3:
add a "magic" standard module Data.Label, which
implicitly exports all possible labels and only such.
that would allow all importers to refer to a common
origin for their label declarations. imports from that
module would amount to declarations of shared label
types: "import Data.Label(mylabel1,mylabel2)"
pro: no syntax extension or separate label namespace,
no problems with common imports
con: no separate label namespace, labels still need to
be declared, by means of import
Either 1 or 3 should be much easier to implement than
full records, and either option would be a small change,
avoiding the main problem of a full records system: that
noone can agree on what the ultimate form should look
like. Either option would enable a pragmatic approach
to the problem while we are waiting for the real records.
What do you think?
Claus
related:
- tweak the existing records system (none)
http://hackage.haskell.org/trac/haskell-prime/ticket/27
- add overlapping or incoherent instances (probably no)
http://hackage.haskell.org/trac/haskell-prime/ticket/54
- add FunctionalDependencies (probably no)
http://hackage.haskell.org/trac/haskell-prime/ticket/36
- add multi parameter type classes (probably yes)
http://hackage.haskell.org/trac/haskell-prime/ticket/49
----------------------------------------
{-# OPTIONS -fglasgow-exts #-}
{-# OPTIONS -fallow-overlapping-instances #-}
-- poor man's records using nested tuples and declared labels:
class Select label val rec | label rec -> val where
sel :: rec -> label -> val
instance Select label val ((label,val),r) where
sel ((_,val),_) label = val
instance Select label val r => Select label val (l,r) where
sel (_,r) label = sel r label
-- some labels and examples
data A = A deriving Show
data B = B deriving Show
data C = C deriving Show
data D = D deriving Show
r1 = ((A,True),((B,'a'),((C,1),())))
r2 = ((A,False),((B,'b'),((C,2),r1)))
x1 r = (r `sel` A, r `sel` B, r `sel` C)
More information about the Haskell-prime
mailing list