1 Introduction to existential types

1.1 Overview

, etc., every type variable that appears on the right-hand side must also appear on the left-hand side. Existential types are a way of turning this off.

1.2 Basics

Existential types can be used for several different purposes. But what they do is to 'hide' a type variable on the right-hand side.

Normally, any type variable appearing on the right must also appear on the left:

data Worker x y = Worker {buffer :: b, input :: x, output :: y}

This is an error, since the type of the buffer isn't specified on the right (it's a type variable rather than a type) but also isn't specified on the left (there's no 'b' in the left part). In Haskell98, you would have to write

data Worker b x y = Worker {buffer :: b, input :: x, output :: y}

That may or may not be an actual problem.

Usually there is no problem at all with this state of affairs (which is why Haskell98 works this way). However, suppose that a

Worker

can use any type 'b' so long as it belongs to some particular class. Then every function that uses a

Worker

will have a type like

foo ::(Buffer b)=> Worker b IntInt

or something. (In particular, failing to write an explicit type signature will invoke the dreaded monomorphism restriction.) Using existential types, we can avoid this:

type at all.
This has a number of consequences. First of all, it is now impossible for a function to demand a

Worker

having a specific type of buffer. Second, the type of

foo

can now be derived automatically without needing an explicit type signature. (No monomorphism restriction.) Thirdly, since code now has no idea what type the

buffer

function returns, you are more limited in what you can do to it.

In general, when you use a 'hidden' type in this way, you will usually want that type to belong to a specific class, or you will want to pass some functions along that can work on that type. Otherwise you'll have some value belonging to a random unknown type, and you won't be able to do anything to it!

Note: You can use existential types to convert a more specific type into a less specific one. (See the examples below.) There is no way to perform the reverse conversion!

2 Examples

2.1 A short example

This illustrates creating a heterogeneous list, all of whose members implement "Show", and progressing through that list to show these items:

However, this does not work as written since the elements of the list can be of SEVERAL different types (like a sphere and a polygon and a mesh etc. etc.) but
lists need to have elements of the same type.

2.2.2 The solution

Use 'existential types' - an extension to Haskell that can be found in most compilers.

2.3 Dynamic dispatch mechanism of OOP

Existential types in conjunction with type classes can be used to emulate the dynamic dispatch mechanism of object oriented programming languages. To illustrate this concept I show how a classic example from object oriented programming can be encoded in Haskell.

3.2 Cases that really require existentials

There are cases where this sort of trick doesn't work. Here are two examples from a haskell mailing list discussion (from K. Claussen) that don't seem expressible without
existentials. (But maybe one can rethink the whole thing :)

data Expr a = Val a |forall b . Apply (Expr (b -> a))(Expr b)

and

data Action =forall b . Act (IORef b)(b ->IO())

(Maybe this last one could be done as a

type Act (IORef b)(IORef b ->IO())

then we could hide the

IORef

as above, that is go ahead and apply the second argument to the first)

3.3 Existentials in terms of "forall"

It is also possible to express existentials as type expressions directly (without a

data

declaration) with RankNTypes. Taking the above example:

data Obj =forall a.(Show a)=> Obj a

the type

Obj

is equivalent to:

forall r.(forall a.Show a => a -> r)-> r

(the leading

forall r.

is optional unless the expression is part of another expression). The conversions are:

Chapter 8 (EH4) of Atze Dijkstra's Essential Haskell PhD thesis (most recent version). A detailed explanation. It explains also that existential types can be expressed in Haskell, but their use is restricted to data declarations, and the notation (using keyword

forall

) may be confusing. In Essential Haskell, existential types can occur not only in data declarations, and a separate keyword