通常我发现自己需要在Haskell 中跳过迭代的其余部分(比如continue在C中):
forM_ [1..100] $ \ i ->
a <- doSomeIO
when (not $ isValid1 a) <skip_rest_of_the_iteration>
b <- doSomeOtherIO a
when (not $ isValid2 b) <skip_rest_of_the_iteration>
...
Run Code Online (Sandbox Code Playgroud)
但是,我没有找到一个简单的方法.我所知道的唯一方法可能是Trans.Maybe,但是有必要使用monad变换来实现如此微不足道的东西吗?
Jus*_* L. 13
请记住,在Haskell中这样的循环并不神奇......它们只是你能自己编写的普通的一流东西.
对于它的价值,我认为将MaybeTMonad变换器视为Monad变压器并不太有用.对我来说,MaybeT只是一个NEWTYPE包装给替代实现的(>>=)...就像你如何使用Product,Sum,First,And,等方面给予的替代实现mappend和mempty.
现在,(>>=)对你而言IO a -> (a -> IO b) -> IO b.但它会是有更多的有用(>>=)这里是IO (Maybe a) -> (a -> IO (Maybe b) -> IO (Maybe b).一旦你进入第一个返回a的动作Nothing,就不可能再"绑定"了.这正是MaybeT给你的东西.您还可以得到一个"自定义实例" guard,guard :: Bool -> IO (Maybe a)的,而不是guard :: IO a.
forM_ [1..100] $ \i -> runMaybeT $ do
a <- lift doSomeIO
guard (isValid1 a)
b <- lift $ doSomeOtherIO a
guard (isValid2 b)
...
Run Code Online (Sandbox Code Playgroud)
就是这样:)
MaybeT也不是魔术,你可以通过使用嵌套的whens 来达到基本相同的效果.这没有必要,只是让事情变得更简单,更清洁:)
以下是使用简单递归的方法:
loop [] = return () -- done with the loop
loop (x:xs) =
do a <- doSomeIO
if ...a...
then return () -- exit the loop
else do -- continuing with the loop
b <- doSomeMoreIO
if ...b...
then return () -- exit the loop
else do -- continuing with the loop
...
loop xs -- perform the next iteration
Run Code Online (Sandbox Code Playgroud)
然后使用以下命令调用它:
loop [1..100]
Run Code Online (Sandbox Code Playgroud)
你可以使用whenControl.Monad中的函数整理一下这个:
loop [] = return ()
loop (x:xs) =
do a <- doSomeIO
when (not ...a...) $ do
b <- doSomeMoreIO
when (not ...b...) $ do
...
loop xs
Run Code Online (Sandbox Code Playgroud)
还有unless在Control.Monad,你可能更愿意使用.
使用@ØrjanJohansen的有用建议,这是一个简单的例子:
import Control.Monad
loop [] = return ()
loop (x:xs) = do
putStrLn $ "x = " ++ show x
a <- getLine
when (a /= "stop") $ do
b <- getLine
when (b /= "stop") $ do
print $ "iteration: " ++ show x ++ ": a = " ++ a ++ " b = " ++ b
loop xs
main = loop [1..3]
Run Code Online (Sandbox Code Playgroud)