Records in Haskell
Barney Hilken
b.hilken at ntlworld.com
Thu Sep 15 18:52:20 CEST 2011
Here is a simple concrete proposal:
Nonextensible records with polymorphic selectors.
=================================================
1. Introduce a built-in class Label, whose members are strings at the type level. We need a notation for them; I will use double single quotes, so ''string'' is automatically an instance of Label, and you can't define other instances.
2. Define a class (in a library somewhere)
class Label n => Contains r n where
type field r n :: *
select :: r -> n -> field r n
update :: r -> n -> field r n -> r
3. Declarations with field labels such as
data C = F {l1 :: t1, l2 :: t2} | G {l2 :: t2}
are syntactic sugar for
data C = F t1 t2 | G t2
instance Contains C ''l1'' where
field C ''l1'' = t1
select (F x y) _ = x
update (F x y) _ x' = F x' y
instance Contains C ''l2'' where
field C ''l2'' = t2
select (F x y) _ = y
select (G y) _ = y
update (F x y) _ y' = F x y'
update (G y) _ y' = G y'
4. Selector functions only need to be defined once, however many types they are used in
l1 :: Contains r ''l1'' => r -> field r ''l1''
l1 = select r (undef ::''l1'')
l2 :: Contains r ''l2'' => r -> field r ''l2''
l2 = select r (undef ::''l2'')
5. Constructors are exactly as before
6. Updates such as
r {l1 = x}
are syntactic sugar for
update r (undef::''l1'') x
=====================================================
This has the advantage that the extension to Haskell is fairly small, and it's compatible with existing user code, but if we later decide we want extensible records, we need only add a type function to order Label lexicographically.
Barney.
More information about the Glasgow-haskell-users
mailing list