繁体   English   中英

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

[英]The Haskell way to do IO Loops (without explicit recursion)?

我想读取一个由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);
                }

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

所以,这是我的尝试:

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)

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

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

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

myReadList = unfoldWhileM (/= "") getLine

是的,为了抽象出前面的答案中提到的显式递归,有一个很有用的Control.Monad.Loop库。 对于那些感兴趣的人来说, 这是一个很好的Monad循环教程

然而,还有另一种方式。 以前,在努力完成这项工作并且知道Haskell是默认的Lazy我首先尝试过;

(sequence . repeat $ getLine) >>= return . takeWhile (/="q")

我希望上面的内容将输入的行收集到IO [String]类型中。 不......它无限期地运行,IOactişons一点也不懒。 此时System IO Lazy也可能派上用场。 它是一个2功能的简单库。

run        :: T a -> IO a
interleave :: IO a -> T a

因此, run Lazy IO操作并将其转换为IO操作,而interleave则相反。 因此,如果我们将上述功能改写为;

import qualified System.IO.Lazy as LIO

gls = LIO.run (sequence . repeat $ LIO.interleave getLine) >>= return . takeWhile (/="q")

Prelude> gls >>= return . sum . fmap (read :: String -> Int)
1
2
3
4
q
10

使用流式传输包的有效流的解决方案:

import Streaming
import qualified Streaming.Prelude as S

main :: IO ()
main = do
    result <- S.toList_ . S.takeWhile (/="") . S.repeatM $ getLine
    print result

一种显示提示的解决方案,使它们与阅读操作分开:

main :: IO ()
main = do
    result <- S.toList_
            $ S.zipWith (\_ s -> s)
                        (S.repeatM $ putStrLn "Write something: ")
                        (S.takeWhile (/="") . S.repeatM $ getLine)
    print result

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM