Reputation: 1069
I'm using ghc extension ExistentialQuantification and got an error on it. I know the s
type of test
's second argument's will not be the same as the s
defined in test
function, but how can I force them to be the same?
1. {-# LANGUAGE ExistentialQuantification #-}
2.
3. data Func = forall s . Func s
4.
5. test :: (s -> a) -> Func -> a
6. test f (Func s) = f s
Got an error:
Untitled..hs:6:21: error:
• Couldn't match expected type ‘s’ with actual type ‘s1’
‘s1’ is a rigid type variable bound by
a pattern with constructor: Func :: forall s. s -> Func,
in an equation for ‘test’
at Untitled..hs:6:9
‘s’ is a rigid type variable bound by
the type signature for:
test :: forall s a. (s -> a) -> Func -> a
at Untitled..hs:5:9
• In the first argument of ‘f’, namely ‘s’
In the expression: f s
In an equation for ‘test’: test f (Func s) = f s
• Relevant bindings include
s :: s1 (bound at Untitled..hs:6:14)
f :: s -> a (bound at Untitled..hs:6:6)
test :: (s -> a) -> Func -> a (bound at Untitled..hs:6:1)
Upvotes: 0
Views: 187
Reputation: 120711
The dual to existential quantification (∃) is universal quantification (∀). The dual being needed because the passed-in function has s
in contravariant position (i.e. it stands left of the function arrow). Passing a universally-quantified function in as a parameter makes the type of test
rank-2, so you need that extension.
{-# LANGUAGE Rank2Types #-}
test :: (forall s . s -> a) -> Func -> a
test f (Func s) = f s
But, note that you won't actually be able to use this in any meaningful way, because the passed in function can't do anything with its argument if if can't know the type. You probably want to add some constraints to both the existential and the universal. Like (I'm using the syntax I'd prefer)
{-# LANGUAGE GADTs, UnicodeSyntax #-}
data Func where
Func :: Show s => s -> Func
test :: (∀s . Show s => s -> a) -> Func -> a
test f (Func s) = f s
A possibly better alternative is to avoid existential quantification (which is often used in a way that's not really Haskell-idiomatic) entirely, in favour of parametric polymorphism:
data Func s = Func s
test :: (s -> a) -> Func s -> a
test f (Func s) = f s
Upvotes: 4