2

我有以下问题:给定 a[String]String->IO Int. 所以我可以进行转换(地图)并得到[IO Int]. 现在,我必须做两件事——从一开始就执行这些操作,直到结果是肯定的,我需要知道,所有列表都已处理。我被禁止在第一个非阳性结果后处理。

takeWhileM不回答第二个问题(长度比较太不切实际),spanM执行禁止IO

当然,我可以自己编写递归函数,但我想以 Haskell 的方式编写,具有所有高阶函数的优点。

建议?可能,完全使用另一种方法?上面的任务是我项目中的一个简化任务。

4

3 回答 3

8

您可以allMmonad-loops使用:

Prelude Control.Monad.Loops> let xs = ["a", "bb", "ccc", "dddd", "eeeee"]
Prelude Control.Monad.Loops> let f x = putStrLn x >> return (length x)
Prelude Control.Monad.Loops> let p x = x < 2
Prelude Control.Monad.Loops> allM (fmap p . f) xs
a
bb
False

还有一个allMin Control.Monad.ListM,但它不是适当的懒惰——它会在你得到一个肯定的结果后继续执行计算。

(顺便说一句,我支持你——我讨厌编写一次性递归函数。)

于 2012-07-31T13:27:00.833 回答
3

我不熟悉这些功能takeWhileMspanM(也不是hoogle)(编辑:根据评论,它们可以在Control.Monad.ListM中找到)。

鉴于此,我认为您最好的做法是创建一个一次性函数来执行此任务。如果后来发现您需要编写代码来做类似的事情,那么您可以分解出公共部分并重新使用它们。一般来说,编写一次性代码并没有错,只是代码重复很糟糕。

有几种方法可以编写您想要的函数 - 一种可能的方法是这样的:

process :: [IO Int] -> IO Bool
process []     = return True
process [a]    = a >> return True
process (a:as) = do
    n <- a
    if n > 0
        then return False
        else process as
于 2012-07-31T11:47:00.497 回答
0

@illusionoflife:我看不出使用takeWhileM会如何改进@Chris 的解决方案。

例如:

import Control.Monad.ListM

process :: [IO Int] -> IO Bool
process as = do
  taken <- takeWhileM (>>= return . (<= 0)) as
  return (length taken >= length as - 1)

(代码未验证!)

@Chris 看起来更具可读性,除其他外,因为在他的解决方案中,我们不需要弄清楚是否应该使用>=or ==。此外,由于我打电话,length我们不能在无限输入列表上使用它。

于 2012-07-31T12:27:15.067 回答