Dmi*_*lov 11 io haskell lazy-sequences
假设,我在使用IO时获得了大量项目:
as <- getLargeList
Run Code Online (Sandbox Code Playgroud)
现在,我想申请fn :: a -> IO b到as:
as <- getLargeList
bs <- mapM fn as
Run Code Online (Sandbox Code Playgroud)
mapM有类型mapM :: Monad m => (a -> m b) -> [a] -> m [b],这就是我在类型匹配方面所需要的.但它会在内存中构建所有链,直到返回结果.我正在寻找模拟器mapM,它会懒散地工作,所以我可以使用头部,bs而尾部仍然在建造.
Gab*_*lez 18
不要使用unsafeInterleaveIO或任何懒惰的IO.这正是创建迭代器以解决的问题:避免惰性IO,这会产生不可预测的资源管理.诀窍是永远不要构建列表并使用迭代器不断地对其进行流式处理,直到您完成使用它为止.我将使用我自己的库中的示例pipes来演示这一点.
首先,定义:
import Control.Monad
import Control.Monad.Trans
import Control.Pipe
-- Demand only 'n' elements
take' :: (Monad m) => Int -> Pipe a a m ()
take' n = replicateM_ n $ do
a <- await
yield a
-- Print all incoming elements
printer :: (Show a) => Consumer a IO r
printer = forever $ do
a <- await
lift $ print a
Run Code Online (Sandbox Code Playgroud)
现在让我们对用户有意义并要求他们为我们制作真正大的列表:
prompt100 :: Producer Int IO ()
prompt100 = replicateM_ 1000 $ do
lift $ putStrLn "Enter an integer: "
n <- lift readLn
yield n
Run Code Online (Sandbox Code Playgroud)
现在,让我们运行它:
>>> runPipe $ printer <+< take' 1 <+< prompt100
Enter an integer:
3<Enter>
3
Run Code Online (Sandbox Code Playgroud)
它只提示用户输入一个整数,因为我们只需要一个整数!
如果你想prompt100用输出替换getLargeList,你只需写:
yourProducer :: Producer b IO ()
yourProducer = do
xs <- lift getLargeList
mapM_ yield xs
Run Code Online (Sandbox Code Playgroud)
...然后运行:
>>> runPipe $ printer <+< take' 1 <+< yourProducer
Run Code Online (Sandbox Code Playgroud)
这将懒惰地流式传输列表,永远不会在内存中构建列表,所有这些都不会使用不安全的IO黑客攻击.要更改所需的元素数量,只需更改传递的值即可take'
欲了解更多像这样的例子,请阅读pipes教程的Control.Pipe.Tutorial.
要了解有关懒惰IO导致问题的原因的更多信息,请阅读Oleg关于主题的原始幻灯片,您可以在此处找到该幻灯片.他在解释使用惰性IO的问题方面做得很好.任何时候你觉得有必要使用惰性IO,你真正想要的是一个iteratee库.
IO monad确实有一种延迟效果的机制.它被称为unsafeInterleaveIO.您可以使用它来获得所需的效果:
import System.IO.Unsafe
lazyMapM :: (a -> IO b) -> [a] -> IO [b]
lazyMapM f [] = return []
lazyMapM f (x:xs) = do y <- f x
ys <- unsafeInterleaveIO $ lazyMapM f xs
return (y:ys)
Run Code Online (Sandbox Code Playgroud)
这就是懒惰IO的实现方式.实际上执行效果的顺序难以预测并且将由结果列表的元素的评估顺序决定,这是不安全的.出于这个原因,重要的是任何IO效应f都是良性的,因为它们应该是顺序不敏感的.通常足够良性的效果的一个很好的例子是从只读文件中读取.