如果IO Bool
中的任何一个Bool
False
测试列表然后在最后执行操作的最佳方式是什么?
如果我有功能检查目录中是否存在给定文件
check :: FilePath -> IO ()
check s = do
r <- doesFileExist s
putStrLn s ++ if r then " exists" else " does not exist"
我希望能够检查文件列表,然后在最后执行另一个功能,具体取决于是否所有测试都通过了?
目前我只能考虑用
之类的东西再次进行检查allPassed = do
l <- mapM doesFileExist [`list of files`]
if all (==True) l then "all ok" else "meh"
答案 0 :(得分:1)
我会像这样使用foldM
:
import Control.Monad
check :: FilePath -> IO Bool
check = undefined
process files = do
allok <- foldM (\b f -> fmap (b &&) (check f)) True files
if allok then putStrLn "All OK" else putStrLn "Oops"
请注意,这将始终执行所有测试。
docs for allM
表示它是短路的,所以
do allok <- allM check files
if allok then ... else ...
将在第一次失败后停止执行检查。
<强>更新强>
以下是一些演示代码:
import Control.Monad
check :: Int -> IO Bool
check x = do putStrLn ("x = " ++ show x)
return $ even x
process files = do
allok <- foldM (\b f -> fmap (b &&) (check f)) True files
if allok then putStrLn "All OK" else putStrLn "Oops"
main = do process [1..5] -- will print "Oops"
process [2,4,6] -- will print "All OK"
答案 1 :(得分:1)
我建议使用allM
包中的Control.Monad.Loops
。如果它看到任何值为false,它会提前退出,如果您的检查涉及一些昂贵的计算,这将非常有用。
这是一个简单的例子:
import Control.Monad.Loops
doesFileExist :: FilePath -> IO Bool
doesFileExist path
| path == "holiday.jpg" = return True
| path == "me.jpg" = return True
| path == "pop song.mp3" = return True
| otherwise = return False
check :: FilePath -> IO Bool
check s = do
r <- doesFileExist s
putStrLn $ s ++ if r
then " exists"
else " does not exist"
return r
main :: IO ()
main = do
allPassed <- allM check ["holiday.jpg", "cat.mp4", "me.jpg"]
if allPassed
then putStrLn "Yes"
else putStrLn "No"