6.12.2. Letgeneralisation¶

MonoLocalBinds
¶ Since: 6.12.1 Infer less polymorphic types for local bindings by default.
An MLstyle language usually generalises the type of any letbound or wherebound variable, so that it is as polymorphic as possible. With the extension MonoLocalBinds
GHC implements a slightly more conservative policy, for reasons descibed in Section 4.2 of OutsideIn(X): Modular type inference with local assumptions,
and a related blog post.
The extension MonoLocalBinds
is implied by TypeFamilies
and GADTs
. You can switch it off again with
NoMonoLocalBinds
but type inference becomes
less predictable if you do so. (Read the paper!)
To a first approximation, with MonoLocalBinds
toplevel bindings are
generalised, but local (i.e. nested) bindings are not. The idea is
that, at top level, the type environment has no free type variables,
and so the difficulties described in these papers do not arise. But
GHC implements a slightly more complicated rule because,
for stylistic reasons, programmers sometimes write local bindings that make no use of local variables, so the binding could equally well be toplevel. It seems reasonable to generalise these.
So here are the exact rules used by MonoLocalBinds. With MonoLocalBinds, a binding group will be generalised if and only if
 It is a toplevel binding group, or
 Each of its free variables (excluding the variables bound by the group itself) is closed (see next bullet), or
 Any of its binders has a partial type signature (see Partial Type Signatures). Adding a partial type signature
f :: _
, (or, more generally,f :: _ => _
) provides a perbinding way to ask GHC to perform letgeneralisation, even though MonoLocalBinds is on.
Even if the binding is generalised, it may not be generalised over all its free type variables, either because it mentions locallybound variables, or because of the Monomorphism Restriction (Haskell Report, Section 4.5.5)
Closed variables. The key idea is that: if a variable is closed, then its type definitely has no free type variables. A variable f
is called closed if and only if
 The variable
f
is imported from another module, or  The variable
f
is letbound, and one of the following holds:f
has an explicit, complete (i.e. not partial) type signature that has no free type variables, or its binding group is generalised over all its free type variables, so that
f
‘s type has no free type variables.
Note that a signature like f :: a > a is equivalent to f :: forall a. a > a
, assuming a
is not in scope. Hence f
is closed, since it has a complete type signature with no free variables.
Example 1
g v = ...
where
f1 x = x+1
f2 y = f1 (y*2)
f1
has free variable (+)
, but it is imported and hence closed. So f1
‘s binding is generalised. As a result, its type f1 :: forall a. Num a => a > a
has no free type variables, so f1
is closed. Hence f2
‘s binding is generalised (since its free variables, f1
and (*)
are both closed).
Example 2
f3 x = let g y = x+y in ....
The binding for g
has a free variable x
that is lambdabound, and hence not closed. So g
‘s binding is not generalised.
Toplevel bindings. The Monomorphism Restriction can cause even toplevel bindings not to be generalised, and hence even the toplevel type environment can have free type variables. However, toplevel bindings are nevertheless always generalised. To see why, consider
module M( f ) where
x = 5
f v = (v,x)
The binding x=5
falls under the Monomorphism Restriction, so that binding is not generalised, and hence f
‘s binding is not closed. If, as a result, we did not generalise f
, we would end up exporting f :: Any > (Any, Integer)
, defaulting x
‘s type to Integer and v
‘s type to Any
. This is counterintuitive and undesirable, so we always generalise toplevel bindings.