A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://www.haskell.org/ghc/docs/latest/html/users_guide/exts/let_generalisation.html below:

Website Navigation


6.12.2. Let-generalisation — Glasgow Haskell Compiler 9.12.2 User's Guide

6.12.2. Let-generalisation¶
MonoLocalBinds¶
Implied by:

TypeFamilies, GADTs

Since:

6.12.1

Status:

Included in GHC2024

Infer less polymorphic types for local bindings by default.

An ML-style language usually generalises the type of any let-bound or where-bound 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 top-level 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 top-level. 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

Even if the binding is generalised, it may not be generalised over all its free type variables, either because it mentions locally-bound 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

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 lambda-bound, and hence not closed. So g's binding is not generalised.

Top-level bindings. The Monomorphism Restriction can cause even top-level bindings not to be generalised, and hence even the top-level type environment can have free type variables. However, top-level 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 counter-intuitive and undesirable, so we always generalise top-level bindings.


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4