Newbie question
Robert Dockins
robdockins at fastmail.fm
Sun Jan 9 08:48:27 EST 2005
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"
More information about the Glasgow-haskell-users
mailing list