In the code below I have defined a data type F using existential quantification. I would like values of type F to hold functions that accept a single argument and produce, say, an Int as the result. The argument needs to implement a type class which I've called C, but left empty for now.
This is my first attempt at existential types. I am clearly doing something wrong as I don't seem to be able to create values of type F.
{-# LANGUAGE ExistentialQuantification #-}
class C a where
data F = forall a. C a => F (a->Int)
makeF :: F
makeF = F $ const 1
How can I fix this compile error?
No instance for (C a0) arising from a use of `F'
In the expression: F
In the expression: F $ const 1
In an equation for `makeF': makeF = F $ const 1
If you rewrite your F
definition as below it will work:
{-# LANGUAGE RankNTypes #-}
class C a where
data F = F (forall a. C a => a -> Int)
makeF :: F
makeF = F $ const 1
I'm trying to understand why myself:
Your original type says "there exists a
which is instance of C
, and we have function a -> Int
".
So to construct existential type, we have to state which a
we have:
{-# LANGUAGE ExistentialQuantification #-}
class C a where
data F = forall a. C a => F (a -> Int)
-- Implement class for Unit
instance C () where
makeF :: F
makeF = F $ (const 1 :: () -> Int)
These aren't exactly equivalent definitions:
data G = forall a . C a => G {
value :: a -- is a value! could be e.g. `1` or `()`
toInt :: a -> Int, -- Might be `id`
}
data G' = G' {
value' :: C a => a -- will be something for every type of instance `C`
toInt' :: C a => a -> Int, -- again, by parametericity uses only `C` stuff
}