Records in Haskell

Barney Hilken b.hilken at
Thu Sep 15 23:04:51 CEST 2011

Typos in my last message: the identifier "field" should be "Field" throughout, and "undef" should be "undefined". Here is the corrected version:

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 (undefined ::''l1'')

	l2 :: Contains r ''l2'' => r -> Field r ''l2''
	l2 = select r (undefined ::''l2'')

5. Constructors are exactly as before

6. Updates such as

	r {l1 = x}

are syntactic sugar for

	update r (undefined::''l1'') x


Sorry about that.


More information about the Glasgow-haskell-users mailing list