Haskell IO从用户读取整数n,然后将n个整数相加

ben*_*ris 1 io recursion haskell

我正在尝试编写一个从用户读取整数n的程序,然后读取n个整数(在单独的行上),最后显示读取的n个数字的总和.

到目前为止,这是我的代码:

addNumbers :: IO ()
addNumbers = do
    putStrLn "Enter a number:"
    num <- getInt
    addNumbers2 num

addNumbers2 :: Int -> IO ()
addNumbers2 num = do
    putStrLn "Enter a number:"
    n <- getInt
    if num == 1 then
        print n
    else do
        print (n + addNumbers2 (num - 1))
Run Code Online (Sandbox Code Playgroud)

目前它没有编译,错误说:

Couldn't match expected type `Int' with actual type `IO ()'
In the return type of a call of `addNumbers2'
In the second argument of `(+)', namely `addNumbers2 (num - 1)'
In the first argument of `print', namely
  `(n + addNumbers2 (num - 1))'
Run Code Online (Sandbox Code Playgroud)

IO真的让我感到困惑,我正在尝试获得以下输出:

Enter a number:
3
Enter a number:
2
Enter a number:
1
Enter a number:
5
Sum is: 8
Run Code Online (Sandbox Code Playgroud)

And*_*ewC 5

你把addNumbers它看作是一个普通的函数,但它是一个IO操作,所以我们只能从里面do和里面得到它的数字answer <- addNumbers2,但是在它没有返回任何东西时,它只是打印它.

我重构了一点:

addNumbers :: IO ()
addNumbers = do
    putStrLn "Enter how many numbers:" -- clearer
    num <- getInt
    sum <- addNumbers2 num  -- use new version to return sum
    print sum               -- print them here
Run Code Online (Sandbox Code Playgroud)

现在addNumbers2实际上添加它们并返回它们:

addNumbers2 :: Int -> IO Int
addNumbers2 num = do
    putStrLn "Enter a number:"
    n <- getInt
    if num == 1 then
        return n      -- pass the number back
    else do
        therest <- addNumbers2 (num - 1) -- get the rest of them
        return (n + therest)             -- add them up
Run Code Online (Sandbox Code Playgroud)

这样可行:

addNumbers
Enter how many numbers:
3
Enter a number:
1
Enter a number:
2
Enter a number:
3
6
Run Code Online (Sandbox Code Playgroud)

一个更好的方法

sequence :: Monad m => [m a] -> m [a]获取操作列表并运行它们,返回结果列表.如果我们只是列出一个或更多的getInts 列表[getInt| _<-[1..num]],replicate num getInt我们就可以做到numbers <- sequence (replicate num getInt).有一个简写Control.Monad,称为replicateM :: Monad m => Int -> m a -> m [a]

尽管如此,这样做会更好:

import Control.Monad

addNumbers' = do
    putStrLn "Enter how many numbers:" 
    num <- getInt
    numbers <- replicateM num (putStrLn "Enter a number" >> getInt)
    print (sum numbers)
Run Code Online (Sandbox Code Playgroud)

这使

Enter how many numbers:
3
Enter a number
10
Enter a number
20
Enter a number
30
60
Run Code Online (Sandbox Code Playgroud)