我有以下问题:给定一个[String]和String->IO Int。因此,我可以进行转换(映射)并获得[IO Int]。现在,我必须做两件事--执行操作,从开始,直到结果是肯定的,我需要知道,所有的列表都被处理了。我被禁止在第一个非正面结果后进行处理。
takeWhileM不回答第二个问题(长度比较太不切实际),spanM执行禁止的IO。
当然,我也可以自己写递归函数,但是我想用Haskell的方式,用高阶函数来实现。
有什么建议吗?也许,使用完全不同的方法?上面的任务是我的项目中的一个简化任务。
发布于 2012-07-31 21:27:01
您可以从the monad-loops package使用allM
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在Control.Monad.ListM中也有一个allM,但它并不是很懒--在你得到一个肯定的结果后,它会继续执行计算。
(顺便说一句,在这一点上我和你一样--我讨厌写一次性的递归函数。)
发布于 2012-07-31 19:47:00
我不熟悉函数takeWhileM和spanM (hoogle也不熟悉)(edit:根据注释,它们可以在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-31 20:27:15
@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的看起来更具可读性,尤其是因为在他的解决方案中,我们不需要考虑应该使用>=还是==。此外,因为我调用了length,所以我们不能在无限输入列表上使用它。
https://stackoverflow.com/questions/11739117
复制相似问题