[Haskell-cafe] a simple question about types

Ryan Ingram ryani.spam at gmail.com
Wed Nov 17 14:19:17 EST 2010


Now of course, the followup question is "what the heck is a
monomorphism restriction and why would I want it?"

Here is a simple example:

expensiveComputation :: Num a => a -> a
expensiveComputation x = ... something that takes a long time to compute ...

ghci> :t (expensiveComputation 2 *)
(expensiveComputation 2 *) :: Num a => a -> a

Now consider these two functions


g = let c = expensiveComputation 2 in (c*)
f x = let c = expensiveComputation 2 in (c*x)

g is a simple pattern binding, so without looking at the RHS, one
expects it to be calculated once and the result shared, in a way like
this:

c = expensiveComputation 2  -- lazily evaluated, only once
g = (c*)

But if you give g the more general type signature, the
expensiveComputation has to get run *every time g is called*.  This is
because there's no way to create a single storage cell for c; there's
a possible answer for every single type that is an instance of Num.

f makes it clear; c does not get evaluated until the arguments are
saturated and is locally allocated.  So it's alright to give it the
polymorphic type.

  -- ryan


On Wed, Nov 17, 2010 at 10:31 AM, Daniel Fischer
<daniel.is.fischer at web.de> wrote:
> On Wednesday 17 November 2010 19:09:16, Jerzy M wrote:
>> Hallo,
>> let me take this simple function: (2*).
>> If I check its type
>>
>> :t (2*)
>>
>> I'll obtain
>> (2*) :: (Num a) => a -> a
>>
>> But now it suffices to write
>> g = (2*)
>> and check
>>
>> :t g
>>
>> to obtain
>> g :: Integer -> Integer
>>
>> One more combination, now I write
>> h x = (2*) x
>> and check once more
>>
>> :t h
>>
>> to get
>> h :: (Num a) => a -> a
>>
>> So my question is: why (in this second example) Integer is inferred?
>> What makes a difference?
>
> The monomorphism restriction.
> As specified in section 4.5.5 of the language report
> (http://www.haskell.org/onlinereport/haskell2010/haskellch4.html#x10-930004.5.5),
> values bound by a (simple) pattern binding (basically, not bound by a
> binding with function arguments to the left of '=') which don't have
> explicit type signatures get a monomorphic type (ambiguous type variables
> are resolved per the defaulting rules of section 4.3 if possible).
>
> So
>
> g = (2*)
>
> is a simple pattern binding without type signature, hence it gets a
> monomorphic type.
> The inferred type is
>
> g :: Num a => a -> a
>
> and by the defaulting rules (unless you have an explicit default
> declaration in the module where g is defined), the ambiguous type variable
> a is resolved to Integer.
>
> h x = (2*) x
>
> is a function binding, hence h gets the inferred polymorphic type.
>
> The MR is often inconvenient (it may be removed in future language
> standards, I'm not up to date with the standings of that proposal), so it
> can be disabled (at least in GHC).
> In normal code, it's not so frequent a matter (on one hand, there's more
> context in the module than at the ghci prompt, on the other hand, modules
> contain more type signatures), so it's comparatively rare to need
> {-# LANGUAGE NoMonomorphismRestriction #-}.
> At the ghci prompt, however, it's a frequent cause of surprise, so it may
> be a good idea to put the line
>
> :set -XNoMonomorphismRestriction
>
> in your ~/.ghci file.
>
> Cheers,
> Daniel
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>


More information about the Haskell-Cafe mailing list