Quantcast

a simple question about types

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

a simple question about types

JerzM
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?

Jerz
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

Alexander Solla-2

On Nov 17, 2010, at 10:09 AM, Jerzy M wrote:


So my question is: why (in this second example) Integer is inferred?
What makes a difference?

I think there are two things going on.  First, the monomorphism restriction is causing the types to be different.  I'm not sure why Integer -> Integer is the default choice, though.  I tend to write the type signatures I want before I write the implementation, so I don't run into these kinds of issues often.


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

Daniel Fischer-4
In reply to this post by JerzM
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
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

Ryan Ingram
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
<[hidden email]> 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
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

Daniel Fischer-4
On Wednesday 17 November 2010 20:19:17, Ryan Ingram wrote:
> 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:
<snip>

>
> 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

That's a most excellent example, thanks.
I hope I find it the next time the topic comes up.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

Jon Fairbairn
In reply to this post by Daniel Fischer-4
Daniel Fischer <[hidden email]> writes:

> 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.

And default. If you load this into ghci

   module Main where

   default (Int)

   g = (2*)
   main = putStrLn "foo"

and type :t g

you'll get Int -> Int

--
Jón Fairbairn                                 [hidden email]



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: a simple question about types

JerzM
Thank you for these excellent explanations.

Best regards,
Jerz
Loading...