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