我在这里有一个关于Haskell IO的问题。我已经在haskell编程已经有一段时间了,但是对于我的爱,我似乎无法绕过I / O.
赋值很简单 - 从标准输入读取整数并将它们相乘。这是我到目前为止所得到的:
mulnum n = do a <- getLine
if a == "" then n else mulnum (n * (read a :: Int))
mulInput :: IO ()
mulInput = print (mulnum 1)
错误:
Couldn't match expected type `IO b' with actual type `Int'
Relevant bindings include
n :: IO b (bound at dayx.hs:8:8)
mulnum :: IO b -> IO b (bound at dayx.hs:8:1)
In the second argument of `(*)', namely `(read a :: Int)'
In the first argument of `mulnum', namely `(n * (read a :: Int))'
In the expression: mulnum (n * (read a :: Int))
我强烈怀疑我是从错误的角度看待它,所以如果有人能指出我正确的方向,我会非常高兴。
谢谢,祝你有愉快的一天!
修改
非常感谢您的帮助!这就是现在的样子:
mulnum :: Int -> IO Int
mulnum n = do a <- getLine
let a1 = (read a :: Int) in if a == "" then return n else mulnum (n * a1)
mulInput :: IO ()
mulInput = mulnum 1 >>= print
答案 0 :(得分:2)
在Haskell中,您通常希望利用懒惰并分离不纯(I / O)和纯(计算)部分。
读取所有行,直到你找到一个空行是I / O.其他一切都是计算。
所以你想要一个能给你输入线的函数,直到你得到一个空的。您可能希望将结果作为字符串列表返回;那已经很懒了。
这样做的一种方法是:
getLines :: IO [String]
getLines = lines <$> getContents
大致意味着&#34;致电getContents
,然后将lines
应用于结果&#34;。 getContents
读取整个标准输入,但它是懒惰的。 lines
将字符串拆分为行;又懒洋洋地说。
(注意:懒惰的I / O有一些问题,导致管道和管道等管道库的开发,但对于这个简单的例子,问题并不重要。)
现在,您只需要在第一个空行处剪切:
main = do
lines <- getLines
let leadingLines = takeWhile (not . null) lines
现在你有了引导线,剩下的就是解析每一行(map
)并乘以它们(这是一个fold
,但是那里是专门的product
就是这样做的。)
这里我们省略检查数字是否正确分析。
let p = (product $ map read leadingLines) :: Int
我添加了一个显式类型注释,因为否则Haskell无法决定你想要的数字类型。
最后,您可以打印出结果。
print p
答案 1 :(得分:0)
您的第一个问题是您只需要说... then return n else ...
你的第二个问题是:
print (mulnum 1)
应该是:
do n <- mulnum 1
print n
或:
mulnum 1 >>= print
说明:
由于您处于IO monad中,因此if-then-else的两个子句都必须是IO计算。 else部分是因为它是对mulnum
的递归调用,但n
本身是纯值。通过写return n
,你可以使它成为monadic。