1

Can anybody explain, why it is valid to read a number to add it to a another number, although reading just a number is not valid?

Prelude> read "5" + 3
8
Prelude> read "5"

:33:1:
    No instance for (Read a0) arising from a use of `read'
    The type variable `a0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance Read () -- Defined in `GHC.Read'
      instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
      instance (Read a, Read b, Read c) => Read (a, b, c)
        -- Defined in `GHC.Read'
      ...plus 25 others
    In the expression: read "5"
    In an equation for `it': it = read "5"

Why is "5" ambiguous?

1 Answer 1

7

"5" itself is not ambiguous, it's more that Haskell does not know to what type you want to read. read is a function defined as:

read :: Read a => String -> a

and you can define multiple types that support the Read class. For instance Int is an instance of Read, but also Float and you can define your own type that is an instance of Read. You could for instance have defined your own type:

data WeirdNumbers = Five | Twelve

and then define an instance Read WeirdNumbers where you map "5" on Five, etc. Now "5" thus maps on several types.

You can simply solve the problem by telling Haskell to what type you want to read. Like:

Prelude> read "5" :: Int
5
Prelude> read "5" :: Float
5.0

The reason why read "5" + 3 works by the way is because here you provide a 3 and a (+) :: Num a => a -> a -> a. So Haskell reasons "Well 3 is an Integer and + requires that the left and the right operand to be of the same type, I know I have to use read such that it reads to an Integer as well."

Sign up to request clarification or add additional context in comments.

4 Comments

It was interesting to learn that the actual signature of Read is more complex and interesting, though for the scope of the question it's not relevant.
@bereal in Haskell, the type signature is almost always extremely relevant. But read is a particularly interesting case IMO as it's one of the most common uses I've come across of return type inference which does not depend on the type of the inputs.
@bereal If read had the type signature String -> Int there would not have been any problem with the OP code. It seems the crux of the matter is indeed that read is polymorphic in the output type. I'm not sure how the problem can be explained without mentioning that general type, unless one only mentions the quick fix "add an annotation" without explaining why is that necessary.
@chi @Matthew what I meant, is that in fact read :: String -> a is not a method of Read a, but Read a is defined in terms of readsPrec :: Int -> ReadS a etc. Sorry if I didn't make it clear.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.