Encoding existentials

Tweet
Posted on December 19, 2016 by Kwang Yul Seo

Existential types are important because Abstract Types Have Existential Type. Haskell supports existential types though a GHC extension named ExistentialQuantification.

Here’s is an example. This code below creates an abstract data type named Obj. Clients of Obj can use only show function because clients can’t know the hidden representation of Obj.

{-# LANGUAGE ExistentialQuantification #-}

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

obj1 :: Obj
obj1 = Obj "hello"

obj2 :: Obj
obj2 = Obj 1

app :: Obj -> String
app (Obj x) = show x

The code is simple, but confusing because it uses forall instead of exists quantifier. It becomes more clear when we rewrite the definition of Obj in GADT syntax.

{-# LANGUAGE GADTs #-}

data Obj where
  Obj :: (Show a) => a -> Obj

As the type variable a no longer appears on the right hand side, it is considered to be existentially quantified. Also you no longer need ExistentialQuantification. Existentials are subsumed by GADTs.

There is another way to encode existential types without ExistentialQuantification. Because an existential type is a pair of type and a value, we can use the Church encoding for a pair to represent existentials.

{∃X,T} = ∀Y. (∀X. T→Y) → Y

In Haskell, we need to enable RankNTypes.

{-# LANGUAGE RankNTypes #-}

type Obj = forall y. (forall x. (Show x) => x -> y) -> y

obj :: Obj
obj f = f "hello"

app :: Obj -> String
app obj = obj (\x -> show x)