Question

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?

Was it helpful?

Solution

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top