Search code examples
haskelltypestype-systemshigher-rank-types

How exactly do type synonyms work?


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?


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