Confusing type specialisation in ghci

Hello, Can someone elucidate to me this behaviour from ghci 6.6.1? Why is the type of sqlist specialised to Integer? Prelude> let sq x = x * x Prelude> :t sq sq :: (Num a) => a -> a Prelude> sq 2.5 6.25 Prelude> :t map sq map sq :: (Num a) => [a] -> [a] Prelude> map sq [2.5] [6.25] This is all as I would expect so far, but: Prelude> let sqlist = map sq Prelude> :t sqlist sqlist :: [Integer] -> [Integer] And indeed, I get Prelude> sqlist [2.5] <interactive>:1:8: No instance for (Fractional Integer) ... etc Thanks! David -- The Wellcome Trust Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.

David Carter wrote:
This is all as I would expect so far, but:
Prelude> let sqlist = map sq Prelude> :t sqlist sqlist :: [Integer] -> [Integer]
And indeed, I get
Prelude> sqlist [2.5]
<interactive>:1:8: No instance for (Fractional Integer) ... etc
The dreaded Monomorphism Restriction, which GHCi chooses to apply after every line you input. You could say "let sqlist a = map sq a" (syntactically having arguments makes the defaulting of (Num a => [a] -> [a]) not apply), or just use `ghci -fno-monomorphism-restriction`. Isaac

Isaac Dupree wrote:
David Carter wrote:
This is all as I would expect so far, but:
Prelude> let sqlist = map sq Prelude> :t sqlist sqlist :: [Integer] -> [Integer]
And indeed, I get
Prelude> sqlist [2.5]
<interactive>:1:8: No instance for (Fractional Integer) ... etc
The dreaded Monomorphism Restriction, which GHCi chooses to apply after every line you input. You could say "let sqlist a = map sq a" (syntactically having arguments makes the defaulting of (Num a => [a] -> [a]) not apply), or just use `ghci -fno-monomorphism-restriction`.
Isaac
Thanks -- I had a feeling I'd seen something about it before, but couldn't remember where. Anyway it's good to know the syndrome has a name and a prevention strategy, even if not a cure :-). David -- The Wellcome Trust Sanger Institute is operated by Genome Research Limited, a charity registered in England with number 1021457 and a company registered in England with number 2742969, whose registered office is 215 Euston Road, London, NW1 2BE.

David Carter wrote:
Prelude> let sqlist = map sq ... Prelude> sqlist [2.5]
<interactive>:1:8: No instance for (Fractional Integer) ... etc
Isaac Dupree wrote:
The dreaded Monomorphism Restriction... You could... use `ghci -fno-monomorphism-restriction`.
...it's good to know the syndrome has a name and a prevention strategy, even if not a cure :-).
I put :set -fno-monomorphism-restriction in my .ghci file. That pretty much cures it for me. -Yitz

You can also remove the Monomorphism Restriction by adding an explicit type signature: Prelude> let sqlist :: Num a => [a] -> [a] ; sqlist = map sq Prelude> :t sqlist sqlist :: (Num a) => [a] -> [a] Basically, there are three things that have to be the case for the MR to kick in: 1) You are defining a function that takes no explicit arguments (or is a pattern binding). 2) You didn't specify a type signature. 3) The inferred most-general-type of the function has typeclass constraints. The reason becomes clear when you consider the following: genericLength :: Num n => [a] -> n -- from Data.List f :: [a] -> (Integer, Integer) f xs = (len, len) where len = genericLength xs (this example taken from http://www.haskell.org/haskellwiki/Monomorphism_restriction) Without the monomorphism restriction, len :: Num n2 => n2. This means len can't be calculated until you know its final type; it's effectively stopped being a shared constant and started being a function. This means that when evaluating the pair (len,len), the length of the list may end up being calculated twice! With the monomorphism restriction, len gets the type Integer, and can be shared. For contrast, consider this function: f2 :: [a] -> (Int, Integer) f2 xs = (len, len) where len :: Num n => n len = genericLength xs In this case, you have no choice but to call genericLength twice, since the result has to be two different types. -- ryan
participants (4)
-
David Carter
-
Isaac Dupree
-
Ryan Ingram
-
Yitzchak Gale