ambiguity error with `reads` in ghc-7.8
ghc, haskell
Solution
The types should unify but don't in the presence of the `NoMonomorphismRestriction` (as noted in the comments by @FedorGogolev and @kosmikus). However, the following more idiomatic approach removes the need for the type annotation in any case:
data LispVal = Atom String
| List [LispVal]
| DottedList [LispVal] LispVal
| Number Integer
| String String
| Bool Bool
unpackNum :: LispVal -> Integer
unpackNum (Number n) = n
unpackNum (String n) = case reads n of
[] -> 0
((x, _):xs) -> x
unpackNum (List [n]) = unpackNum n
unpackNum _ = 0
The Difference Between Case and Null
It boils down to the fact that `null` is a function whereas `case` is straight syntax.
null :: [a] -> Bool
So with -XNoMonomorphismRestriction enabled, this is left as polymorphic as possible when the argument is supplied. The function doesn't restrict the argument type in any way, and so the compiler is unable to determine the return type of `reads`, causing the error. At the site of the function call, the type is ambiguous. In the case of the `case` statement, the compiler has the entire expression to work with, and so has the pattern matches to refine the return type of `reads`.
Problem
I am testing the code for Write yourself a Scheme in 48 hours with GHC-7.8.2, which gives me an error about ambiguity that I don't recall encountering in previous versions of GHC. The excerpt is below, with the problem line marked: ``` data LispVal = Atom String | List [LispVal] | DottedList [LispVal] LispVal | Number Integer | String String | Bool Bool unpackNum :: LispVal -> Integer unpackNum (Number n) = n unpackNum (String n) = let parsed = reads n in --problem line if null parsed then 0 else fst $ parsed !! 0 unpackNum (List [n]) = unpackNum n unpackNum _ = 0 ``` , and the error says: ``` No instance for (Read a0) arising from a use of ¡®parsed¡¯ The type variable ¡®a0¡¯ is ambiguous Note: there are several potential instances: instance Read a => Read (Control.Applicative.ZipList a) -- Defined in ¡®Control.Applicative¡¯ instance Read () -- Defined in ¡®GHC.Read¡¯ instance (Read a, Read b) => Read (a, b) -- Defined in ¡®GHC.Read¡¯ ...plus 26 others ``` If I change the problem line to ``` unpackNum (String n) = let parsed = reads n ::[(Integer,String)] in ``` then everything works fine. I don't see why GHC failed to infer the type for ReadS from the signature of `unpackNum`. Can someone please explain what triggered the error? ( -- EDIT -- Just some follow-up. From what I understand, the function type `unpackNum :: LispVal -> Integer` and the fact that `fst $ parsed !! 0` is a return value of it tells that `parsed` has type `[(Integer,b)]`, and from `type ReadS a = String -> [(a,String)]`, the `parsed` should be `[(a, String)]`. Shouldn't these two types unify to `[(Integer, String)]` and fix the type for `parsed`? Can someone please explain why `NoMonomorphismRestriction` would break the above reasoning? -- EDIT2 -- From the answers, I can understand how `NoMonomorphismRestriction` could cause the issue here. Still, what I don't understand is the fact that how this "two type for the same expression" behavior consistent with laziness in Haskell. In the example `parsed` or `reads n` is the same expression in one block and should be evaluated only once. How can it have type `a` the first time of evaluation and `Integer` the second time? ) Thanks,