3

In my attempt to understand existential types I've read that Church encoding along with the Rank-N-types extension would be sufficient to encode them in Haskell without existential quantification. I found this straightforward example:

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)

In the Haskell Wiki I stumbled upon the following example of a heterogeneous list based on an existential type:

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

xs :: [Obj]
xs = [Obj 1, Obj "foo", Obj 'c']

doShow :: [Obj] -> String
doShow [] = ""
doShow ((Obj x):xs) = show x ++ doShow xs

Now I tried to express this implementation with Church and failed with an illegal polymorphic type error:

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

obj1 :: Obj 
obj1 f = f 1 

obj2 :: Obj 
obj2 f = f "foo" 

obj3 :: Obj 
obj3 f = f 'c' 

xs :: [Obj] 
xs = [obj1, obj2, obj3]

doShow :: [Obj] -> String 
doShow [] = "" 
doShow (obj:xs) = obj (\x -> show x ++ doShow xs)

I guess this translation is pretty schematic and just plain wrong. Is it right that existential types can be encoded with Church/Rank-N? How is it done properly?

  • 6
    No, you did it. It's just that Haskell does not allow *impredicative polymorphism*, that is to say type constructors (other than `(->)`) with polymorphic types. You will find the same error if you try to create any value of e.g. type `[forall a. a]`. If you wrap `Obj` in a `newtype` instead of a type synonym, I think this approach will work. (Unfortunately it doesn't buy you anything over the existential approach since you still need to wrap values in a constructor) – luqui Jun 25 '17 at 08:58
  • Technically, this small program will work if you enable `ImpredicativeTypes`; but this extension [doesn't really work](https://stackoverflow.com/questions/39220435/why-are-higher-rank-types-so-fragile-in-haskell/39230655#39230655) so chances are you will hit a wall sooner or later, and be unable to proceed. You won't be able to use `foldr :: .. -> .. -> [Obj] -> ..` or basically any higher order list function. – user2407038 Jun 25 '17 at 16:27
  • 1
    Also note calling this a 'heterogenous' list is not really correct; `[Obj]` is a list which stores values of exactly one type - `Obj`. `Obj` itself does not somehow store values of many different types - it is isomorphic to `Int -> ShowS`, which is the type of `showsPrec` partially applied to its second argument: `showsPrec :: Show a => Int -> a -> ShowS`. This makes `[Obj]` nothing more than a fancy and inconvenient way to write `[Int -> ShowsS]` - the latter type is predicative and unfathomably easier to work with. – user2407038 Jun 25 '17 at 16:31
  • @luqui I had to look more closely at _impredicative polymorphism_ to understand your comment. Very helpful, thanks! –  Jun 25 '17 at 17:02
  • 1
    @user2407038 I don't want to proceed with this approach actually. It just helps me to understand the underlying concepts. Usually it isn't so hard for me to understand new topics. But with Haskell it's different. Especially the type system is hard to grasp due to all these abstractions/generalizations. –  Jun 25 '17 at 17:11

0 Answers0