Search code examples
haskelltypesfunctional-programmingghctype-declaration

How to relate to type from outer context


Let us consider the following code snippet:

blah :: a -> b -> a
blah x y = ble x where
    ble :: b -> b
    ble x = x

This compiles fine under GHC, which essentially means that b from the 3rd line is something different than b from the first line.

My question is simple: is there a way to somehow relate in the type declaration of ble to a type used in an outer context, i.e. the type declaration of blah?

Obviously, this is just an example and not a real-world use-case for type declarations.


Solution

  • This is possible with the ScopedTypeVariables extension. You need to use explicit forall's to bring the type variables into scope.

    blah :: forall a b. a -> b -> a
    blah x y = ble x where
        ble :: b -> b
        ble x = x
    

    Trying to load this definition with ScopedTypeVariables enabled gives:

    foo.hs:2:16:
        Couldn't match type `a' with `b'
          `a' is a rigid type variable bound by
              the type signature for blah :: a -> b -> a at foo.hs:2:1
          `b' is a rigid type variable bound by
              the type signature for blah :: a -> b -> a at foo.hs:2:1
        In the first argument of `ble', namely `x'
        In the expression: ble x
        In an equation for `blah':
            blah x y
              = ble x
              where
                  ble :: b -> b
                  ble x = x
    

    You can tell that GHC interprets the two bs as the same type because the error says that a and b are bound on the same line.