Constructors in GHC

Simon Peyton-Jones
Wed, 11 Dec 2002 11:40:39 -0000

This message is to air a possible change in the way GHC handles
constructors.  Before I make the change I want to check that it isn't
going to mess anyone up.  There's some background in

Consider the following
	data T =3D MkT !(Int,Int)
	f x y =3D MkT (x,y)
	g (MkT (x,y)) =3D x

If you compile this with -funbox-strict-fields, GHC will unbox the
strict pair, to give effectively this
	data T =3D MkT Int Int
	f x y =3D MkT x y
	g t =3D case t of MkT x y -> x

Rather than find all the applications of MkT, it actually *defines* MkT
like this

	MkT p =3D case p of (x,y) -> $wMkT x y

where $wMkT is the "real" constructor.  So the "real" data type is

	data T =3D $wMkT Int Int

and MkT is just a "wrapper function".  However in Core-language case
expressions we still print 'MkT':
	g t =3D case t of
	  	 MkT a b -> ...

even though the "real" constructor is $wMkT.  (On the face of it, MkT a
b isn't even well typed.)

This is a bit of a mess, especially when we print External Core.  Then
we get
	data T =3D MkT Int Int
	MkT p =3D case p of (x,y) -> $wMkT x y
	f x y =3D $wMkT x y
	g t =3D case t of MkT x y -> x

Strange!  MkT looks like the constructor for T, but is also given a
definition; and $wMkT doesn't seem to be defined at all.  This gives
rise to difficulties when reading External Core back in.

We could make this more consistent in two ways.  Alternative (A): One
way would be to make it clearer that $wMkT was the real constructor:

	data T =3D $wMkT Int Int
	MkT p =3D case p of (x,y) -> $wMkT x y
	f x y =3D $wMkT x y
	g t =3D case t of $wMkT x y -> x

This is consistent, but it makes External Core a bit funny.  (The real
constructors are always $w things.) =20

Alternative (B): The other alternative would be to make the original
Haskell constructors into the $w things:

	data T =3D MkT Int Int
	$wMkT p =3D case p of (x,y) -> MkT x y
	f x y =3D MkT x y
	g t =3D case t of MkT x y -> x

This makes Core (and External Core) nice and consistent, with
traditional upper-case constructors, but MkT now has a different type
than in the original program.  We'd need to take care when printing type
errors etc that we didn't print $wMkT when the programmer expected MkT.
(That isn't too hard.)

Personally, I'm inclined to alternative (B).  Do any of you have an
opinion?  Especially folk using External Core?