[Haskell-cafe] Rigid type variables and their role in type checking

Brandon Allbery allbery.b at gmail.com
Wed Aug 24 16:29:46 UTC 2016

On Wed, Aug 24, 2016 at 11:49 AM, Morten Olsen Lysgaard <morten at lysgaard.no>

> Lastly consider:
> foo3 :: a -> Int
> foo3 x = x
> The inferred type of `foo3` is, again, `foo3 :: t -> t`, when unified with
> the annotated type, `a -> Int`, we find that `t` must have the same type as
> `a`, and `t` must be of type `Int`, thus `t = a = Int`. Everything works
> out!?

I mentioned this when you were asking about this in IRC, but you may have
missed it.

All type variables are implicitly qualified at top level in standard
Haskell (and in ghc if they are not explicitly qualified at some level).
Thus the actual type signature is

    foo3 :: forall a. a -> Int

and (forall a. a) does *not* unify with Int. This does not work in both
directions, though; in your second example, the *inferred* type (t -> t) is
permitted to unify with an explicitly specified type (Int -> Int). It is
only explicitly specified types that do this (this is what "rigid" means:
explicitly specified, therefore not permitted to unify with a more specific

The reason for this is that the type signature specifies the contract with
callers. (a -> a) which means (forall a. a -> a) promises the caller you
will accept any (a) the *caller* chooses. This is why such explicit
signatures are rigid: you promised the caller you will accept any (a), so
you may not renege on that contract and always produce (Int).

brandon s allbery kf8nh                               sine nomine associates
allbery.b at gmail.com                                  ballbery at sinenomine.net
unix, openafs, kerberos, infrastructure, xmonad        http://sinenomine.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/haskell-cafe/attachments/20160824/1cee9da2/attachment.html>

More information about the Haskell-Cafe mailing list