您可以使用ListT
from pipes
,它为惰性提供了一种更安全的替代方案,IO
在这种情况下可以做正确的事情。
您对可能失败的图像的惰性流建模的方式是:
imageStream :: ListT IO (Maybe Image)
假设您有一些类型的图像加载功能:
loadImage :: FileName -> IO (Maybe Image)
..那么您构建这样一个流的方式将类似于:
imageStream = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
lift $ loadImage fileName
如果您使用dirstream
library,那么您甚至可以懒惰地流式传输目录内容。
仅过滤出成功结果的函数将具有以下类型:
flattenImageStream :: (Monad m) => ListT m (Maybe a) -> ListT m a
flattenImageStream stream = do
ma <- stream
case ma of
Just a -> return a
Nothing -> mzero
请注意,此函数适用于任何基本 monad m
,. 没有什么IO
具体的。它还保留了懒惰!
应用flattenImage
到imageStream
,给我们一些类型的东西:
finalStream :: List IO Image
finalStream = flattenImage imageStream
现在假设您有一些使用这些图像的函数,类型为:
useImage :: Image -> IO ()
如果要ListT
使用useImage
函数处理最终结果,只需编写:
main = runEffect $
for (every finalStream) $ \image -> do
lift $ useImage image
这将懒惰地消耗图像流。
当然,您也可以玩代码高尔夫并将所有这些组合成以下更短的版本:
main = runEffect $ for (every image) (lift . useImage)
where
image = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
maybeImage <- lift $ loadImage fileName
case maybeImage of
Just img -> return img
Nothing -> mzero
我也在考虑添加一个fail
定义,ListT
这样你就可以写:
main = runEffect $ for (every image) (lift . useImage)
where
image = do
fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"]
Just img <- lift $ loadImage fileName
return img