Jose Emilio Labra Gayo wrote:

 | > data ITEM = forall i . Item i => MkItem i

Don't get me wrong, I think existential types are very useful, but in some
cases the answer is just around the corner in Haskell98, not needing
exisistential types at all.

In this case this could be possible as well.

Suppose your class definition of ITEM looks something like:

  class Item i where
    foo :: i -> Int
    bar :: i -> Bool

This means that, after wrapping an object of type i as an ITEM, the only
things you can do with that object are to either apply foo or bar to it.
Why don't we already do that (we are lazy functional programmers, aren't
we?), and define the following type for ITEM:

  data ITEM = MkItem { appliedFoo :: Int, appliedBar :: Bool }

We can introduce a helper function to make things easier:

  mkItem :: Item i => i -> ITEM
  mkItem i = MkItem{ appliedFoo = foo i, appliedBar = bar i }

It is clear that this has the same "strength" as the original definition,
but we're not using exisitential types.

Even when the class Item is a little bit more complicated, for example:

  class Item i where
    foo  :: i -> Int
    step :: i -> i

We can still use laziness to solve this. What can we do after we have
wrapped a value into an ITEM? We can apply step to it an arbitrary number
of times, and then we can apply foo to that result.

So, we make an infinite list of the possible things we can do:

  data ITEM = MkItem { nStepsThenFoo :: [Int] }

And a helper function:

  mkItem :: Item i => i -> ITEM
  mkItem i = MkItem { nStepsThenFoo = map foo (iterate step i) }

Note that, because of laziness, we will actually only compute the result
when we take it out.

I have applied this method several times when I thought I needed
existential types, but I didn't need them at all. I think this might be
the case more often.

Regards,
Koen.

--
Koen Claessen,
[EMAIL PROTECTED],
http://www.cs.chalmers.se/~koen,
Chalmers University of Technology.



Reply via email to