views:

89

answers:

1

read is defined in the Prelude as

read :: (Read a) => String -> a

and can be used as e.g. read "1" :: Int.

Now a function

readOne :: (Read a) => [String] -> (a, [String])
readOne (x:xs) = (read x,xs)

used with readOne ["1","foo"] results (as expected) in the error

Ambiguous type variable 'a' in the constraint:
'Read a' arising from a use of 'readOne' at :1:0-18
Probable fix: add a type signature that fixes these type variable(s)

But readOne ["1","foo"] :: Int doesn't work, while

readOneInt :: [String] -> (Int, [String])
readOneInt = readOne

works just fine:

> readOneInt ["1", "foo"]
(1,["foo"])

So: how can I add a type signature to readOne without defining a new function like readOneInt?

+7  A: 

readOne ["1","foo"] :: Int doesn't work because readOne couldn't possibly return an Int, it always returns a tuple, whose second element is a [String]. readOne ["1", "foo"] :: (Int, [String]) will work.

Note that you only need to specify the type if it can't be inferred. If you use the result of readOne in a context where it needs to be an Int, you can use readOne without type annotations. Example:

let inc (i, strs) = (i + 1, strs) in
inc (readOne ["1", "foo"])
-- (2, ["foo"])
sepp2k
Thank you very much!
Greg S
Beware! The example at the end will only work in ghci because the type of 1 is defaulted to `Integer`. If you ask ghci for the type of the expression (via `:t`), you get `(Num a, Read a) => (a, [String])` which has the same problem as before. `asTypeOf` can help here, as in `asTypeOf (readOne ["1", "foo"]) (0::Double,[]::[String])` - which I would normally write with asTypeOf in backticks but SO doesn't like doubly-escaped backticks.
yatima2975