Dear Rune, This might be the magic moment for shifting to the `foldl` library (`cabal install foldl`). Then you can keep pretty much everything you have from above, but slide in other independent components like logging or debugging and other stuff, e.g. a final count of blocks processed, as you please. Part of the reason `Pipes.Prelude.fold` has the type it has it to make it interoperate with 'Control.Foldl`.
To use the library, instead of directly applying `Pipes.Prelude.fold` to `step` `begin` and `done` defined above, you will 'reify' the fold, to start with. That is, instead of writing foldBlocks :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocks initialBlockState = Pipes.Prelude.fold step begin done where step e block = do blockState <- e process blockState block begin = return initialBlockState done = id you will write blockFold : BlockState -> Control.Foldl.Fold Block (Either String BlockState) blockFold initialBlockState = Control.Foldl.Fold step begin done where step e block = do blockState <- e process blockState block begin = return initialBlockState done = id then the function defined earlier is recovered with a use of `purely` from Control.Foldl foldBlocks :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocks initialBlockState = Control.Foldl.purely Pipes.Prelude.fold (blockFold initialBlockState) `purely` just extracts the components of the 'reified fold' and feeds them to a suitably defined fold from another library. ( Here, it is the pipes fold function, but there are similar functions elsewhere like say http://hackage.haskell.org/package/mono-traversable-0.9.3/docs/Data-MonoTraversable.html#v:ofoldlUnwrap ) So far our results are as before, but with this little fold reifying bit. Once we've expressed our `foldBlocks` with a `Control.Foldl.Fold`, we can start adding stuff. For example given Control.Foldl.length :: Fold a Int we can immediately complicate `foldBlocks` to also give a count of blocks processed. blockFoldWithLength : BlockState -> Control.Foldl.Fold Block (Int,Either String BlockState) blockFoldWithLength initialState = liftA2 (,) Control.Foldl.length (blockFold initialState) so now we can trivial alter our processing function to foldBlocksWithLength :: BlockState -> Producer Block IO () -> IO (Int, Either String BlockState) foldBlocksWithLength initialBlockState = Control.Foldl.purely Pipes.Prelude.fold (blockFoldWithLength initialBlockState) But the problem wasn't to snap a pure component like block count into our fold, but to snap in an impure logging component. So we are using the `FoldM` type from `Control.Foldl`, not the `Fold` type. No problem, we already have a `FoldM` on our hands: blockFoldM : Monad m => BlockState -> Control.Foldl.FoldM m Block (Either String BlockState) blockFoldM initialState = generalize (blockFold initialState) and we could as well have written our initial `foldBlocks` as: foldBlocks :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocks initialBlockState = Control.Foldl.impurely Pipes.Prelude.foldM (blockFoldM initialBlockState) but now we have it in a shape where we can snap in a logger function. We might do this by hand writing something with this shape loggerFold :: Handle -> Control.FoldM IO Block () loggerFold = FoldM step begin done where step x block = undefined -- new 'IO x' whatever it is, probably IO () begin = undefined -- initial IO x, probably 'return ()' done _ = return () -- given I assumed () in the signature So it is a question of writing `step` to do whatever you want to be logged from each block. Then you will just write: foldBlocksWithLogging :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocksWithLogging initialBlockState = Control.Foldl.impurely Pipes.Prelude.foldM (blockFoldM initialBlockState <* loggerFold) or foldBlocksWithLogging :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocksWithLogging initialBlockState = Control.Foldl.impurely Pipes.Prelude.foldM (generalize (blockFold initialBlockState) <* loggerFold) a sufficiently trivial logger can be written with L.sink :: (Monad m, Monoid w) => (a -> m w) -> L.FoldM m a w the ultra-minimal debugging fold would be blockAlertFoldM :: FoldM IO Block () blockAlertFoldM = sink (\block -> putStrLn "Block Processed!") then we have, e.g. foldBlocksWithAlert :: BlockState -> Producer Block IO () -> IO (Either String BlockState) foldBlocksWithAlert initialBlockState = Control.Foldl.impurely Pipes.Prelude.foldM (generalize (blockFold initialBlockState) <* loggerFold) and could start throwing in other components foldBlocksWithAlertAndLength :: BlockState -> Producer Block IO () -> IO (Int, Either String BlockState) foldBlocksWithAlertAndLengh initialBlockState = Control.Foldl.impurely Pipes.Prelude.foldM myfolds where myfolds = generalize mypurefolds <* loggerFold mypurefolds = liftA2 (,) Control.Foldl.length (blockFold initialBlockState) Here we get the block count at the end, and are printing "Block processed!" to stdout as each block is processed. There are probably a few gruesome type and typing errors in the above, but I hope it makes the Control.Foldl approach to your problem clear. I probably managed to cross some crucial consideration of importance to Gabriel, but it's always pleasing to find out... -- You received this message because you are subscribed to the Google Groups "Haskell Pipes" group. To unsubscribe from this group and stop receiving emails from it, send an email to haskell-pipes+unsubscr...@googlegroups.com. To post to this group, send email to haskell-pipes@googlegroups.com.