我们可以创建一个辅助函数,它在返回值时重复给定的操作:
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
while :: (Monad m) => MaybeT m b -> m ()
while k = runMaybeT (forever k) >> return ()
一旦k返回mzero,循环停止。然后我们可以使用标准MonadPlus组合器很好地使用它在任何地方中断循环:
main = while $ do
l <- lift getLine
guard $ l /= "quit"
lift $ putStrLn l
或者在一行:
main = while $ mfilter (/= "quit") (lift getLine) >>= lift . putStrLn
更新:也许最简单的解决方案是使用whileJust_from monad-loops:
isValid s | s /= "quit" = Just s
| otherwise = Nothing
main = whileJust_ (isValid `liftM` getLine) putStrLn