haskell - 显示 Haskell 程序的进度

标签 haskell functional-programming

我在 Haskell 中有一些对象的列表。我需要查明这些对象中是否有人满足某些条件。所以,我写了以下内容:

any (\x -> check x) xs

但问题是检查操作的开销非常大,而且列表也很大。我想查看运行时的当前进度,例如 50%(选中 1000/2000)。
我怎样才能做到这一点?

最佳答案

由于您想查看函数的进度(这是函数的副作用),最明显的解决方案是使用 monad。因此,首先要做的是制作 any 函数的单子(monad)版本:

anyM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM _ []        = return False
anyM pred (x:xs) = reduce (pred x) xs
    where reduce acc []     = acc
          reduce acc (x:xs) = do
              condition <- acc
              if condition
                  then return condition
                  else reduce (pred x) xs

上面的函数 anyMany 函数的单子(monad)版本。除了检查给定列表中的任何项目是否满足给定谓词之外,它还允许我们产生副作用。

除了执行 any 函数之外,我们还可以使用 anyM 函数创建另一个函数,该函数显示进度条作为副作用,如下所示:

anyVar :: (a -> Bool) -> [a] -> IO Bool
anyVar pred xs = anyM check $ zip [1..] xs
    where check (n,x) = do
            putStrLn $ show n ++ " checked. "
            return $ pred x

请注意,由于我们事先不知道列表的长度,因此我们只显示列表中检查的项目数。如果我们事先知道列表中的项目数,那么我们可以显示信息更丰富的进度条:

anyFix :: (a -> Bool) -> Int -> [a] -> IO Bool
anyFix pred length xs = anyM check $ zip [1..] xs
    where check (n,x) = do
            putStrLn $ show (100 * n `div` length) ++ "% (" ++
                show n ++ "/" ++ show length ++ " checked). "
            return $ pred x

对于无限列表和您事先不知道长度的列表,请使用 anyVar 函数。对您事先知道其长度的有限列表使用 anyFix 函数。

如果列表很大并且您事先不知道列表的长度,则 length 函数将需要遍历整个列表以确定其长度。因此,最好使用 anyVar 来代替。

最后,总结一下这就是如何使用上述函数:

main = anyFix (==2000) 2000 [1..2000]

根据您的情况,您可以执行以下操作:

main = anyVar check xs

希望这个回答对你有帮助。

关于haskell - 显示 Haskell 程序的进度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19343695/

相关文章:

haskell - 如何创建特殊类型的列表?

haskell - OverloadedStrings 语言扩展如何工作?

haskell - 将 Haskell 函数转换为 SML

flutter - 事件的返回函数

haskell - 是否有类型为 : (Floating a, RealFrac b) => a -> b 的标准 Haskell 函数?

haskell - 在 Haskell 中制作小写字符串列表

haskell - 避免捕获替换函数 — Lambda 演算

python - numpy.max 的惰性求值

functional-programming - Racket 博士,帮助从列表中获取元素

scala - 使用反射和解释器动态解析字符串并在 Scala 中返回一个函数