[Haskell-cafe] Phantoms

Jason Dagit dagit at codersbase.com
Thu Aug 14 02:43:37 EDT 2008


On Wed, Aug 6, 2008 at 11:09 AM, Andrew Coppin
<andrewcoppin at btinternet.com>wrote:

> I just (re)discovered that I can do things like
>
>  data Foo x = Foo Int Int
>
> Now "Foo Int" and "Foo Double" are, as far as the type checker cares, two
> completely different types, even though in fact they are the same. This is
> actually Quite Useful, in the particular case I'm working on.


Phantom types are indeed useful for many things, but a bit of cautionary
advice.  If you start to depend on the phantoms for type safety AND you
export your data constructors then you run a serious risk of being type
unsafe.  Bonus points if you can demonstrate an equivalent of unsafeCoerce#
this way.

Example:
fooCast :: Foo Int -> Foo Double
fooCast (Foo x) = Foo x

On noes!  We just cast that Foo Int to a Foo Double without changing it!  It
works because the value on the RHS is consider freshly constructed and other
than sharing x it is unrelated to the one on the LHS.

Note that by contrast this does not type check:
foo :: Foo Int -> Foo Double
foo f@(Foo x) = f

Or, for that matter, any other variant where you don't use the constructor
on the RHS.

One way to get around this is to create your own constructor functions:

mkFooInt :: Int -> Foo Int
mkFooInt = Foo

mkFooDouble :: Int -> Foo Double
mkFooDouble = Foo

Now export these instead of your data constructor.  Similarly you'll
probably want ones to take the place of pattern matching.  The most obvious
general purpose one being:
unFoo :: Foo a -> Int
unFoo (Foo a) = a

But, if you're really relying on that phantom as a "witness", then you
should probably define separate unFooInt :: Foo Int -> Int and unFooDouble :
Foo Double -> Int.

Here is the part where it gets really interesting.  If you use GADTs, it
rolls some of the above into one nice declaration:

data Foo a where
  FooInt :: Int -> Foo Int
  FooDouble :: Int -> Foo Double

I'm not sure if the GADT way can lead to an unsafeCoerce# equivalents or
not.  Maybe someone else can comment on that.

Jason
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20080813/aa330faf/attachment.htm


More information about the Haskell-Cafe mailing list