So this is a situation where you would use `Pipes.Prelude.foldM` and the solution would look something like this:

foldBlocks :: BlockState -> Producer BlockState IO () -> IO (Either String BlockState)
    foldBlocks initialBlockState = Pipes.Prelude.foldM step begin done
      where
step :: Either String BlockState -> Block -> IO (Either String BlockState)
        step (Right blockState) block = do
            print "your progress information here"
            return (process blockState block)
        step (Left str        ) _     = do
            return (Left str)

        begin :: IO (Either String BlockState)
        begin = return (Right initialBlockState)

        done :: Either String BlockState -> IO (Either String BlockState)
        done = return

On 10/1/15 3:56 AM, Rune Kjær Svendsen wrote:
How would I go about printing log messages, while folding Blocks into the BlockState? The fold may take tens of minutes to complete, so printing information about the processing would be very useful.

Printing a message every time a block is read is simple, because reading a block from the disk already happens in the IO monad. The fold "step" function is pure, so producing a log file requires using something other than Pipes.Prelude.fold, as far as I can see.

Is there a better alternative?



/Rune


On Thursday, October 1, 2015 at 6:26:57 AM UTC+2, Rune Kjær Svendsen wrote:

    THANK you very much for your concise and prompt reply, this was
    exactly what I needed. And yes, I was using Pipes.Prelude.foldM,
    without much success.

    It works beautifully now.

    Cheers!



    /Rune


    On Thu, Oct 1, 2015 at 5:53 AM, Gabriel Gonzalez
    <gabr...@gmail.com> wrote:
    > Use `Pipes.Prelude.fold`, which has this type:
    >
    >     fold :: Monad m => (x -> a -> x) -> x -> (x -> b) ->
    Producer a m () ->
    > m b
    >
    > The trick is realizing that this works if we specialize the `a`,
    `x`, and
    > `b` type parameters to:
    >
    >     a = Block
    >     x = Either String BlockState
    >     b = Either String BlockState
    >
    > 95% of the work is just figuring out what the type of your
    accumulator (i.e.
    > the type parameter`x`) should be.  Once you figure that out it's
    all
    > downhill from there.
    >
    > ... and also specialize `m` to `IO`, which would give us:
    >
    >     fold
    >         :: (Either String BlockState -> Block -> Either String
    BlockState)
    >         -> Either String BlockState
    >         -> (Either String BlockState -> Either String BlockState)
    >         -> Producer Block IO () -> IO (Either String BlockState)
    >
    > That means that we need to pass `fold` three functions of type:
    >
    >     step  :: Either String BlockState -> Block -> Either String
    BlockState
    >     begin :: Either String BlockState
    >     done  :: Either String BlockState -> Either String BlockState
    >
    >     fold step begin done :: Producer Block IO () -> IO (Either
    String
    > BlockState)
    >
    > We can create the `step` function from your `processBlock`
    function:
    >
    >     step :: Either String BlockState -> Block -> Either String
    BlockState
    >     step e block = do
    >         blockState <- e
    >         process blockState block
    >
    > The `done` function is really easy:
    >
    >     done :: Either String BlockState -> Either String BlockState
    >     done = id
    >
    > ... and the `begin` function requires us to supply some sort of
    beginning
    > state:
    >
    >     begin :: Either String BlockState
    >     begin = return initialBlockState -- We'll get
    `initialBlockState`
    > elsewhere
    >
    > ... so we can combine those together to write up the complete
    function:
    >
    >     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
    >
    > Now to give a high-level explanation of what is going on.
    >
    > You probably tried to originally solve this by using
    `Pipes.Prelude.foldM`
    > but you noticed that the `Either` monad didn't match up with the
    > `Producer`'s base monad, `IO`.  However, you can still use
    > `Pipes.Prelude.fold` if you do all the `Either` monad work
    within the fold
    > itself.  In other words, the step function does the binding
    instead of
    > relying on the fold to do the binding for you.
    >
    > On 9/30/15 8:40 PM, Rune Kjær Svendsen wrote:
    >
    > Hello list,
    >
    > I have a Producer of the following type:
    >
    >     blockProducer :: Handle -> Producer Block IO ()
    >
    > which reads Blocks from a file with the given handle, and yields
    a block
    > one-by-one until EOF is reached.
    >
    > I also have a function of the following type:
    >
    >     processBlock :: BlockState -> Block -> Either String BlockState
    >
    > which takes an initial BlockState, and updates it with Block,
    and returns
    > either Right BlockState if no error occurs, or Left String if an
    error
    > occurs.
    >
    > So I want to create a Pipe that consumes Blocks from
    blockProducer, folds
    > them as if I were using (foldlM processBlock), and yields the
    resulting
    > Either String BlockState.
    >
    > How do I do that?
    > --
    > 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
    <mailto:haskell-pipes%2bunsubscr...@googlegroups.com>.
    > To post to this group, send email to
    haskell-pipes@googlegroups.com
    <mailto:haskell-pipes@googlegroups.com>.
    >
    >


--
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.

Reply via email to