Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Specific type inference using uncurry function

I've been playing with the uncurry function in GHCi and I've found something I couldn't quite get at all. When I apply uncurry to the (+) function and bind that to some variable like in the code below, the compiler infers its type to be specific to Integer:

Prelude> let add = uncurry (+)
Prelude> :t add
add :: (Integer, Integer) -> Integer

However, when ask for the type of the following expression I get (what I expect to be) the correct result:

Prelude> :t uncurry (+)
uncurry (+) :: (Num a) => (a, a) -> a

What would cause that? Is it particular to GHCi?

The same applies to let add' = (+).

NOTE: I could not reproduce that using a compiled file.

like image 268
Cesar Barata Avatar asked Feb 15 '11 01:02

Cesar Barata


2 Answers

This has nothing to do with ghci. This is the monomorphism restriction being irritating. If you try to compile the following file:

add = uncurry (+)
main = do
    print $ add (1,2 :: Int)
    print $ add (1,2 :: Double)

You will get an error. If you expand:

main = do
    print $ uncurry (+) (1,2 :: Int)
    print $ uncurry (+) (1,2 :: Double)

Everything is fine, as expected. The monomorphism restriction refuses to make something that "looks like a value" (i.e. defined with no arguments on the left-hand side of the equals) typeclass polymorphic, because that would defeat the caching that would normally occur. Eg.

foo :: Integer
foo = expensive computation

bar :: (Num a) => a
bar = expensive computation

foo is guaranteed only to be computed once (well, in GHC at least), whereas bar will be computed every time it is mentioned. The monomorphism restriction seeks to save you from the latter case by defaulting to the former when it looks like that's what you wanted.

If you only use the function once (or always at the same type), type inference will take care of inferring the right type for you. In that case ghci is doing something slightly different by guessing sooner. But using it at two different types shows what is going on.

When in doubt, use a type signature (or turn off the wretched thing with {-# LANGUAGE NoMonomorphismRestriction #-}).

like image 157
luqui Avatar answered Sep 21 '22 23:09

luqui


There's magic involved in extended defaulting rules with ghci. Basically, among other things, Num constraints get defaulted to Integer and Floating constraints to Double, when otherwise there would be an error (in this case, due to the evil monomorphism restriction).

like image 24
sclv Avatar answered Sep 22 '22 23:09

sclv