I've got a function whose job is to compute some optimal value of type a
wrt some value function of type a -> v
type OptiF a v = (a -> v) -> a
Then I have a container that wants to store such a function together with another function which uses the values values:
data Container a = forall v. (Ord v) => Cons (OptiF a v) (a -> Int)
The idea is that whoever implements a function of type OptiF a v
should not be bothered with the details of v
except that it's an instance of Ord
.
So I've written a function which takes such a value function and a container. Using the OptiF a v
it should compute the optimal value wrt val
and plug it in the container's result
function:
optimize :: (forall v. (Ord v) => a -> v) -> Container a -> Int
optimize val (Cons opti result) = result (opti val)
So far so good, but I can't call optimize
, because
callOptimize :: Int
callOptimize = optimize val cont
where val = (*3)
opti val' = if val' 1 > val' 0 then 100 else -100
cont = Cons opti (*2)
does not compile:
Could not deduce (v ~ Int)
from the context (Ord v)
bound by a type expected by the context: Ord v => Int -> v
at bla.hs:12:16-32
`v' is a rigid type variable bound by
a type expected by the context: Ord v => Int -> v at bla.hs:12:16
Expected type: Int
Actual type: Int
Expected type: Int -> v
Actual type: Int -> Int
In the first argument of `optimize', namely `val'
In the expression: optimize val cont
where line 12:16-32 is optimize val cont
.
Am I misunderstanding existential types in this case? Does the forall v
in the declaration of optimize
mean that optimize
may expect from a -> v
whatever v
it wants? Or does it mean that optimize
may expect nothing from a -> v
except that Ord v
?
What I want is that the OptiF a v
is not fixed for any v
, because I want to plug in some a -> v
later on. The only constraint I'd like to impose is Ord v
. Is it even possible to express something like that using existential types (or whatever)?
I managed to achieve that with an additional typeclass which provides an optimize
function with a similar signature to OptiF a v
, but that looks much uglier to me than using higher order functions.