[Haskell-beginners] let in GHCI

Daniel Fischer daniel.is.fischer at googlemail.com
Sun Dec 11 19:54:37 CET 2011


On Sunday 11 December 2011, 19:14:56, Henry Lockyer wrote:
> Hello Haskellers
> 
> Why is it that in GHCI I can do, for example,
> 
> > let my6 = replicate 6
> > my6 5
> 
> [5,5,5,5,5,5]
> 
> but if I do
> 
> > sort "bav"
> 
> "abv"
> 
> this is ok, but
> 
> > let mySort = sort

It's the monomorphism restriction.
If a value is bound by a simple pattern binding (let val = whatever) 
without a type signature, and if the inferred type is constrained by some 
class requirements, the value gets a monomorphic type, any constrained type 
variables are resolved according to the defaulting rules in
http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-790004.3.4

The first example has no constrained type variables,

replicate :: Int -> a -> [a]

so

my6 :: a -> [a]

is parametric, it works the same for all types. Therefore it remains 
polymorphic.

But

sort :: Ord a => [a] -> [a]

has a constrained type variable, so a value bound like

let mySort = sort

gets a monomorphic type, the constrained type variable a is replaced with a 
fixed type according to defaulting rules.

Since the defaulting rules in the linked section require one of the 
constraining classes to be a numeric class, that binding should be a static 
error by these rules.

However, strict adherence to the defaulting rules would produce a *lot* of 
type errors at the ghci prompt, so ghci has extended defaulting rules, 
resolving more cases, for example, Show, Eq and Ord constraints (with no 
numeric constraint around) are satisfied by instantiating the constrained 
type variable with ().

Thus the binding

> let mySort = sort

at the ghci prompt results in

> :t mySort
mySort :: [()] -> [()]

You get the inferred (most general) type if you

1) bind the value with a function binding (one with at least one argument 
before the =),

> let mySort xs = sort xs

2) give a polymorphic type signature

> let mySort :: Ord a => [a] -> [a]; mySort = sort

3) disable the monomorphism restriction

> :set -XNoMonomorphismRestriction
> let mySort = sort

It's often a good idea to disable the monomorphism restriction at the ghci 
prompt by default, so you might consider doing that in your .ghci file.


If the monomorphism restriction so often leads to surprising and confusing 
results, why does it exist at all?

Because without it, there'd be another surprising and unpleasant result.
If you have something that looks like a constant,

name = value

you'd likely expect it to be evaluated only once. But if name got a 
polymorphic type, it would have to be re-evaluated for every use.
To avoid the unpleasant surprise of bad performance due to re-evaluation, 
we have the monomorphism restriction.

If you give it a polymorphic signature ore bind it via a function binding, 
it's obvious that the value isn't shared and has to be recalculated.

Is that a sufficiently good reason to have the MR?
Opinions differ.



More information about the Beginners mailing list