
Hello! I am learning Haskell according to the "Yet Another Haskell Tutorial" by Hal Daume Ill. One of the exercises involves a) asking the user to enter several numbers (while the end of the sequence is indicated by entering 0) b) calculate the sum of those numbers. The program given below tries to do that. I can read a list of strings. Then, I try to convert the list of strings into a list of numbers by means of map. That is, given a list ["1","2","3"], I want to convert it into [1,2,3]. In GHCi, this is done via map read ["1","2","3"] However, when I apply this same call in my program below, I'm getting following error when loading the program in GHCi: <error-message> Loading package base ... linking ... done. Compiling Main ( AskForNumbers.hs, interpreted ) AskForNumbers.hs:10: Couldn't match `IO' against `[]' Expected type: IO t Inferred type: [b] In the application `map read words' In a 'do' expression: map read words Failed, modules loaded: none. </error-message> Line 10 corresponds to the statement map read words, which seems to work in GHCi. What am I doing wrongly? Thanks in advance Dmitri Pissarenko PS: What follows is my Haskell program. module Main where import IO main = do hSetBuffering stdin LineBuffering words <- askForNumbers printWords words map read words putStrLn "The sum is" foldl (+) 0 words askForNumbers = do putStrLn "Please enter a number:" text <- getLine if text == "" then return [] else if text == "0" then return [] else do rest <- askForNumbers return (text : rest) printWords [] = putStrLn "EOL" printWords (h : t) = do putStrLn h printWords t

Dmitri Pissarenko
a) asking the user to enter several numbers (while the end of the sequence is indicated by entering 0) b) calculate the sum of those numbers.
...
Here is a corrected version:
module Main where
import IO
Delete this.
main = do hSetBuffering stdin LineBuffering
This is extraneous - stdin should be line buffered by default.
words <- askForNumbers printWords words map read words putStrLn "The sum is" foldl (+) 0 words
Here you map read over words and discard the result. Then you wold over the words and produce an interger, whereas you should produce an IO value from the do block. Here is a complete implementation (untested): main = do words <- askForNumbers mapM_ putStrLn words putStrLn "EOL" let nums = map read words print nums putStrLn "The sum is" print (foldl (+) 0 nums) - Einar Karttunen

comments inline...
module Main where
import IO
main = do hSetBuffering stdin LineBuffering words <- askForNumbers printWords words map read words putStrLn "The sum is" foldl (+) 0 words
as you noted "map read words" is a problematic line. The problem that GHC tells you about is that "map read words" creates a value of type (Read a) => [a], where but each line in an IO do block needs to have type IO a. THe "foldl (+) 0 words" line has the same problem; it's not an IO value. A trick you can use is to use "let" to bind a pure value inside a do block, see below. I seems to me that you are thinking that "map read" will alter "words" from a list of Strings to a list of Ints. This is a fundamental no-no in a pure functional language like Haskell. What you want is to create a new list of integers from your "words" list. The following changes makes your program work. main = do hSetBuffering stdin LineBuffering words <- askForNumbers printWords words --map read words let ints = map read words putStrLn "The sum is" --foldl (+) 0 words putStrLn (show (foldl (+) 0 ints))
askForNumbers = do putStrLn "Please enter a number:" text <- getLine if text == "" then return [] else if text == "0" then return [] else do rest <- askForNumbers return (text : rest)
This is pretty verbose and (IMO) hard to read. I'd probably write it this way: askForNumbers = do putStrLn "Pleas enter a number:" text <- getLine case text of "" -> return [] "0" -> return [] _ -> askForNumbers >>= return . (text:)
printWords [] = putStrLn "EOL" printWords (h : t) = do putStrLn h printWords t
This could also be more succinct with "sequence_", although increased redability is arguable. printWords x = sequence_ (map putStrLn x) >> putStrLn "EOL"
participants (3)
-
Dmitri Pissarenko
-
Einar Karttunen
-
Robert Dockins