0
votes

The Haskell tutorial states that:

  • by looking at the type signature of read

    read :: Read a => String -> a

  • it follows that GHCI has no way of knowing which type we want in return when running

    ghci> read "4"

Why is it necessary to provide a second value from which GHCI can extract a type to compare with?

Wouldn't it be feasible to check a single value against all possible types of the Read typeclass?

Reference: http://learnyouahaskell.com/types-and-typeclasses

3
What concrete type do you propose read "5" should have? It's not so simple to saysara
It's worse than that. Usually you don't use read "5", because you'd just write 5. What concrete type should read someUnknownString have?Ben
Error reading / parsing is the same result as success. For example, in cases where I expect a number, and the user has transmitted something else, then I would like to receive an parsing error, and not something else.freestyle
The type signatures are not really similar at all. show is polymorphic in its argument type - which is something quite normal. But read is polymorphic in its result type, which means without either being told explicitly by a type signature, or inference from the other functions you use the result with, the compiler can't figure out what you want.Robin Zigmond
You say, "Why is it necessary to provide a second value?". This question confuses me. It is not necessary -- and indeed, in most settings, not even allowed -- to provide a second value. For example, read "4" 3 will give you a missing instance error (in the absence of certain very unorthodox additional code). Can you give an example of what you mean, since you don't seem to be using standard terminology here?Daniel Wagner

3 Answers

3
votes

I think you have a (rather common among beginners - I had it myself) misunderstanding of what type classes are. The way Haskell works is logically incompatible with "check[ing] a single value against all possible types of the Read typeclass". Instance selection is based on types. Only types.

You should not think of read as a magical function that can return many types. It's actually a huge family of functions, and the type is used to select which member of the family to use. It's that direction of dependence that matters. Classes create a case where values (usually functions, but not always) - the things that exist at run time - are chosen based on types - the things that exist at compile time.

You're asking "Why not the other direction? Why can't the type depend on the value?", and the answer to that is that Haskell just doesn't work that way. It wasn't designed to, and the theory it was based on doesn't allow it. There is a theory for that (dependent types), and there are extensions being added to GHC that support an increasing set of feature that do some aspect of dependent typing, but it's not there yet.

And even if it was, this example would still not work the way you want. Dependent types still need to know what type something is. You couldn't write a magical "returns anything" version of read. Instead, the type for read would have to involve some function that calculates the type from the value, and inherently only works for the closed set of types that function can return.

Those last two paragraphs are kind of an aside, though. The important part is that classes are ways to go from types to values, with handy compiler support to automatically figure it out for you most of the time. That's all they were designed to do, and it's all that they can do. There are advantages to this design, in terms of ease of compilation, predictability of behavior (open world assumption), and ability to optimize at compile time.

2
votes

Wouldn't it be feasible to check a single value against all possible types of the Read typeclass?

Doing that would yield the same result; read "4" can potentially be anything that can be read from a String, and that's what ghci reports:

Prelude> :t read "4"
read "4" :: Read a => a

Until you actually do the parsing, the Read a => a represents a potential parsing result. Remember that typeclasses being open means that this could potentially be any type, depending on the presence of the instances.

It's also entirely possible that multiple types could share the same Show/Read textual representation, which brings me to my next point...

If you wanted to check what type the string can be parsed as, that would at the very least require resolving the ambiguity between multiple types that could accept the given input; which means you'd need to know those types beforehand, which Read can't do. And even if you did that, how do you propose such value be then used? You'd need to pack it into something, which implies that you need a closed set again.

All in all, read signature is as precise it can be, given the circumstances.

2
votes

Not meant as an answer, but this wouldn't fit into a comment cleanly.

In ghci, if you simply do a read "5", then ghci is going to need some help figuring out what you want it to be. However, if that result is being used somewhere, ghci (and Haskell in general) can figure out the type. For (a silly) example:

add1 :: Int -> Int
add1 i = i + 1

five = read "5"

six = add1 five

In that case, there's no need to annotate the read with a type signature, because ghc can infer it from the fact that five is being used in a function that only takes an Int. If you added another function with a different signature that also tried to use five, you'd end up with a compile error:

-- Adding this to our code above
-- Fails to compile
add1Integer :: Integer -> Integer
add1Integer i = i + 1

sixAsInteger = add1Integer five