Existential types: want better syntactic support (autoboxing?)

Duncan Coutts duncan.coutts at worc.ox.ac.uk
Mon Jan 30 13:02:48 EST 2006


On Mon, 2006-01-30 at 18:13 +0100, Sebastian Sylvan wrote:
> Seems like a convenient feature to me.
> 
> Also, you may want to have a function which works on a list of any
> values which are both readable and showable.
> Say (mockup syntax):
> 
> foo :: <Show a, Read a> => [a]
> foo = [ 1, True, myRocketLauncher ]
> 
> Which would create a newtype called "ShowReadAble" or something with
> extistential types and also instantiate that type in both Show and
> Read.
> 
> I do agree that this is something I'd like in a lot of cases, and it
> probably would be used quite a bit more if it were convenient (and
> standardised!).
> 
> I leave it to someone else to figure out how to make this play nice
> with e.g. type inference.

I have often thought that it would be useful to have an existential
corresponding to a class.

There are several examples in Haskell where one wants to manipulate
lists of values that support a common interface but are not necessarily
the same type.

Haskell makes it very convenient to do type based static dispatch but
rather inconvenient to do runtime value dispatch. In general the
preference for type based static dispatch is good. In OOP languages
people often use the OOP value based dispatch when the Haskell style
would be more appropriate, but it is not convenient in those languages.

On the other hand there are sometimes when it really is better to do the
value base dispatch. For example an extensible IO Handle data type. It
is necessary to have lists of Handles so we can't have a Handle type
class. One could have a record of functions.

When I thought about this before I came to the conclusion that it would
be convenient to be able to have a type class and a corresponding data
type with the same name. The class gives the interface and the data type
can be made a member of the type:

class IStream s where
  readBlock :: s -> IO Block

data IStream = IStream {
  istream_readBlock :: IO Block
}

instance IStream IStream where
  readBlock s = istream_readBlock s

abstractIStream :: IStream s => s -> IStream
abstractIStream s = IStream { istream_readBlock = readBlock s }


So this allows us to have a type class so we can do ordinary type class
stuff or if we need to manipulate streams of different underlying types
only via their IStream interface then we can use abstractIStream to
convert any instance of the IStream class to its most general instance,
namely the IStream data type.

But the above translation is a bit cumbersome and could be optimised.
What's really going on is we're just converting from a class dictionary
to an explicit dictionary. If this sort of thing were supported directly
in the language then the dictionary conversion would be a no-op.

So to summarise the feature, it might be nice to make doing runtime
value-based dispatch through an interface (almost as) easy as the
existing class mechanism which allows static type-based dispatch through
an interface. Also to allow explicit conversion from one form to the
other (anything in the class to a most general instance).

Duncan



More information about the Haskell-prime mailing list