You can use ListT from pipes , which provides a safer alternative to lazy IO , which does the right thing in this case.
How do you model your lazy stream of potentially bad images:
imageStream :: ListT IO (Maybe Image)
Assuming you have an image loading function like:
loadImage :: FileName -> IO (Maybe Image)
.. the way you build such a stream will be something like:
imageStream = do fileName <- Select $ each ["file1.jpg", "file2.jpg", "file3.jpg"] lift $ loadImage fileName
If you use the dirstream library , you can even lazily flow through the contents of the directory.
A function that filters out only successful results will be of the following type:
flattenImageStream :: (Monad m) => ListT m (Maybe a) -> ListT ma flattenImageStream stream = do ma <- stream case ma of Just a -> return a Nothing -> mzero
Note that this function works for any base monad, m . There is nothing IO . He also keeps laziness!
Applying flattenImage to an imageStream gives us something like:
finalStream :: List IO Image finalStream = flattenImage imageStream
Now let's say that you have a function that consumes these images, such as:
useImage :: Image -> IO ()
If you want to process the final ListT using the useImage function, you simply write:
main = runEffect $ for (every finalStream) $ \image -> do lift $ useImage image
This will lazily consume the image stream.
Of course, you can also play golf code and combine all this into the following much shorter version:
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
I am also thinking of adding a fail definition for ListT so you can simply write:
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