
Jason Dagit wrote:
On Wed, Aug 6, 2008 at 11:09 AM, Andrew Coppin
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.
This would be very bad, but I doubt it is possible.
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!
What's the problem?
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.
Right. You must call the data constructor Foo in order to exploit that it has the type Foo :: Int -> Foo a I don't see how this is not type safe, and I was not able to produce an #unsafeCoerce with this technique. One would need some unFoo a -> a but the a in data Foo a is phantom, i.e. there is no thing of type a in a Foo. Cheers Ben