读取行直到空字符串,然后将它们相乘

时间:2015-11-17 11:09:57

标签: haskell io monads

我在这里有一个关于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

2 个答案:

答案 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。