我正在尝试编写一个从用户读取整数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))
目前它没有编译,错误说:
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))'
IO让我感到困惑,我正在努力获得输出:
Enter a number:
3
Enter a number:
2
Enter a number:
1
Enter a number:
5
Sum is: 8
答案 0 :(得分: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
现在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
有效:
addNumbers
Enter how many numbers:
3
Enter a number:
1
Enter a number:
2
Enter a number:
3
6
sequence :: Monad m => [m a] -> m [a]
获取操作列表并运行它们,返回结果列表。如果我们只列出getInt
,[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)
给出了
Enter how many numbers:
3
Enter a number
10
Enter a number
20
Enter a number
30
60
答案 1 :(得分:2)
您可以(并且应该)使用可用的组合器
addNumbers2 n = do
n_numbers <- replicateM n (putStrLn "Number, please: " >> getInt)
let result = sum n_numbers
return result
关键的洞察力是结合IO行动
putStrLn "string" :: IO ()
getInt :: IO Int
到
(putStrLn "Number?" >> getInt) :: IO Int
所以我们有一个IO动作,要求输入并读取它。
现在,我们可以使用
replicateM :: Int -> IO a -> IO [a]
由于我们传递了返回Int
的IO操作,因此我们会返回Int
的列表。
numbers <- replicateM n (putStrLn "Number?" >> getInt)
运行给定的IO动作n次并收集结果。 剩下的就是将数字相加并在IO Monad中返回它们。 或者,如果您只想打印总和,也可以
replicateM n (putStrLn "Number?" >> getInt) >>= putStrLn . show . sum
答案 2 :(得分:2)
以下基于pipes
的解决方案与已接受的解决方案相比具有一个小优势,即它不会在大量行上堆叠溢出:
import Pipes
import qualified Pipes.Prelude as Pipes
main = do
numLines <- readLn
total <- Pipes.sum (Pipes.replicateM numLines readLn)
print total
使用示例:
$ ./example
3<Enter>
10<Enter>
20<Enter>
30<Enter>
60