Why is this happening?
In your second function, it is clear that readMaybe line used as String -> Maybe Int , since type inference notices that you are using return x , and therefore x must be Int .
In your first function, you donβt use Maybe , you just want to check if read succeeded. However, since you did not specify a type (neither explicit nor implicit with the output type), the type variable is ambiguous:
_ -> case readMaybe line of
Itβs easy to fix there: annotate type:
_ -> case readMaybe line :: Maybe Int of
By the way, this is exactly the same behavior that you encounter when using read in ghci without any type context:
> read "1234"
<interactive>: 10: 1:
No instance for (Read a0) arising from a use of `read '
The type variable `a0 'is ambiguous
Once you clear the type, everything is fine:
> read "1234" :: Int
1234
Clarification of things
Now that we have seen why the error occurred, make this program much easier. First of all, we will use custom readMaybe :
readMaybeInt :: String -> Maybe Int readMaybeInt = readMaybe
Now how to count numbers? Numbers are those words where readMaybeInt does not return Nothing :
countNumbers :: String -> Int countNumbers = length . filter isJust . map readMaybeInt . words
How to calculate numbers in standard input now? We simply enter the input until one line is completely empty, match countNumbers with all these lines, and then sum :
lineNumberCount :: IO Int lineNumberCount = getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
If you do not use binding methods, this is basically
lineNumberCount :: IO Int lineNumberCount = do input <- getContents return . sum . map countNumbers . takeWhile (/= "") . lines $ input
In general, we get the following short solution:
import Control.Monad (liftM) import Data.Maybe (isJust) import Text.Read (readMaybe) readMaybeInt :: String -> Maybe Int readMaybeInt = readMaybe countNumbers :: String -> Int countNumbers = length . filter isJust . map readMaybeInt . words lineNumberCount :: IO Int lineNumberCount = getContents >>= return . sum . map countNumbers . takeWhile (/= "") . lines
Now in the IO-monad there is only one function, and all functions are basically applications of standard functions. Note that getContents will close the standard input descriptor. If you want to use, you better use something like
input :: String -> IO [String] input delim = do ln <- getLine if ln == delim then return [] else input delim >>= return . (ln:)
which will retrieve rows until a row matching delim . Note that you need to change lineNumberCount in this case:
lineNumberCount :: IO Int lineNumberCount = input "" >>= return . sum . map countNumbers