Skip to content

Read

Read is the class of all types that can be read, that is, parsed. Given a string representation of a value of such a type, read will convert this string representation into the corresponding value. For example,

GHCi
>>> read "5" :: Int
5

Here, we have to specify the type we expect the return value of read to have because GHCi doesn't have enough context to infer the type. We could also parse the same string as a Double:

GHCi
>>> read "5" :: Double
5.0

If we use read in an expression or function definition where the compiler can infer the expected return type from the context, we do not need to specify the return type. For example,

GHCi
>>> 1.0 / read "5"
0.2

For the Read class, I won't even list the class definition. This class is built to support more than simple conversion from strings to values. It is possible to use the functions supported by types that are instances of Read to build simple parsers for expressions over these types. This is clearly more complex than simple conversion from strings to values, and the methods of the Read class reflect this added complexity. The good news is that every type that is an instance of Read also supports a function read to convert a string to a value of this type:

GHCi
>>> :info read
read :: Read a => String -> a   -- Defined in ‘Text.Read’

Note, however, that read isn't a great choice to parse text that may be malformatted. When you try to do this, read throws an error:

GHCi
>>> read "5.0" :: Int
*** Exception: Prelude.read: no parse

Here, the string "5.0" represents a floating point number, but we asked it to parse it as an Int. That's not possible, so read throws an exception.

If you do want to parse an expression that may be malformed, it is better to use reads:

GHCi
>>> reads "5.0" :: [(Int,String)]
[]
>>> reads "5.0" :: [(Float,String)]
[(5.0,"")]
>>> reads "5.0a" :: [(Float,String)]
[(5.0,"a")]

reads returns a list of pairs. For every valid parse, the list contains a pair consisting of the parsed value and a string containing the characters not consumed during parsing. In the first example, we ask for a list of type [(Int,String)], which means that we try to parse "5.0" as an integer. Since there is no valid parse of this as an integer, the result is the empty list. in the second example, we expect a list of type [(Float,String)], that is, we try to parse "5.0" as a floating point number. Since this is possible, we obtain the list [(5.0,"")]. The string is empty in this case because the entire input "5.0" is parsed as a floating point number. In the last example, we have the additional character a after 5.0. In this case, reads parses 5.0 as a Float and does not consume the a. So the result is [(5.0,"a")].

For simple types, such as Int, Bool, Double, etc., the list produced by reads is always either empty or contains a single pair. The ability to return multiple possible parses is used only when building simple expression parsers.