How does it come, that the following type checks
{-# LANGUAGE RankNTypes #-}
module Main where
class Foo a where
type FunFoo = (Foo a) => a -> IO ()
data Bar = Bar {
funFoo :: FunFoo
}
setFunFoo :: FunFoo -> Bar -> Bar
setFunFoo action bar = bar {funFoo = action}
but when changing the type signature off setFunFoo to
setFunFoo :: ((Foo a) => a -> IO ()) -> Bar -> Bar
it does not? Is there a way to express the above code without the type synonym FunFoo?
You need to add an explicit forall
like so:
setFunFoo :: (forall a. (Foo a) => a -> IO ()) -> Bar -> Bar
The reason for this is because you want the scope of the type variable a
to be limited to the type of the first argument to setFunFoo
. Without the explicit forall
, the desugared type is this:
setFunFoo :: forall a. ((Foo a) => a -> IO ()) -> Bar -> Bar