我在Haskell中列出了一些对象。而且我需要找出这些对象中是否有人满足特定条件。所以,我写了以下内容:
any (\x -> check x) xs
但是问题是检查操作非常昂贵,而且清单很大。我想查看运行时的当前进度,例如
50% (1000/2000 checked).
我该怎么做? 最佳答案
因为您想查看函数的进度(这是函数的副作用),所以最明显的解决方案是使用monad。因此,首先要做的是制作any
函数的单声道版本:
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
上面的
anyM
函数是any
函数的单声道版本。除了检查给定列表中的任何项是否满足给定谓词外,它还可以产生副作用。除了执行
anyM
函数外,我们还可以使用any
函数创建另一个函数,该函数显示进度条作为副作用。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/