Darkmantis
Darkmantis

Reputation: 13

Recursion in Haskell - Sum of number read from keyboard

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

Answers (1)

chepner
chepner

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

Related Questions