Reputation: 13
I'm trying sum numbers read from the keyboard but i don't get it, in the function sumNums for example i put 7 and i can input 8 numbers but just add 7, i want that input 7 and add 7. In the main function i don't get to use sumNums
getInt :: IO Int
getInt = do
s <- getLine
return (read s)
sumNums :: Integer -> IO Int
sumNums n = do
x<-getInt
if n==0
then return 0
else do
rest <- sumNums (n-1)
return (x+rest)
main = do putStrLn "Type numbers: "
suma <- sumNums 7
putStrLn "Sum: " ++ show sum
average <- suma/7
putStrLn "Average: " ++ show average
Upvotes: 1
Views: 986
Reputation: 530843
The main problem is that you read a number, then you check if the value of n
indicates you should be reading another number. Instead, check the value of n
first.
sumNums 0 = return 0
sumNums n = do
rest <- sumNums (n - 1)
x <- getInt
return (x + rest)
However, you should try to avoid explicit recursion when you can. Many common patterns have already been abstracted away behind higher-order functions.
Here, what do you want? You want to sum a list of numbers, which you can get by running getInt
some number of times. Start with the replicate
function to repeat getInt
the desired number of times:
> :t replicate 3 getInt
replicate 3 getInt :: [IO Int]
Then use sequence
to extract all the integers into a single list.
> :t sequence (replicate 3 getInt)
sequence (replicate 3 getInt) :: IO [Int]
Finally, you can lift sum
into the IO
monad to add up the numbers.
> :t sum <$> sequence (replicate 3 getInt)
sum <$> sequence (replicate 3 getInt) :: IO Int
Thus, you can write sumNums
simply as
sumNums n = sum <$> sequence (replicate n getInt)
More simply, replicateM
combines sequence
with replicate
(effectively, replicateM = (sequence . ) . replicate
).
import Control.Monad
sumNums n = sum <$> replicateM n getInt
Upvotes: 3