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
.