Haskell做IO循环的方式(没有显式递归)?

Agn*_*yay 4 monads recursion haskell loops

我想阅读STDIN中换行符分隔的字符串列表,直到看到一个新行并且我想要一个类型的动作IO [String].这是我如何使用递归来做到这一点:

myReadList :: IO String
myReadList = go []
where 
    go :: [String] -> IO [String]   
    go l = do {
                 inp <- getLine;
                 if (inp == "") then 
                     return l;
                 else go (inp:l);
                }
Run Code Online (Sandbox Code Playgroud)

然而,这种使用方法模糊了可读性,并且是一种非常普遍的模式,理想情况下,人们希望将其抽象出来.

所以,这是我的尝试:

whileM :: (Monad m) => (a -> Bool) -> [m a] -> m [a]
whileM p []     = return []
whileM p (x:xs) = do
    s <- x
    if p s
    then do
        l <- whileM p xs
        return (s:l)
    else
        return []

myReadList :: IO [String]
myReadList = whileM (/= "") (repeat getLine)
Run Code Online (Sandbox Code Playgroud)

我猜这里有一些默认的实现whileM或类似的东西.但是我找不到它.

有人能指出处理这个问题的最自然和优雅的方法是什么?

Hog*_*ama 12

unfoldWhileM与你的whileM相同,只是它将一个动作(不是列表)作为第二个参数.

myReadList = unfoldWhileM (/= "") getLine
Run Code Online (Sandbox Code Playgroud)