Search code examples
haskellconduit

Implementing an accumulating function using Conduit


I am exploring the possibility to use the Conduit package in order to implement complex event processing in Haskell. As an example, I would like to implement an accumulating function using Conduit.

Starting from:

#!/usr/bin/env stack
-- stack script --resolver lts-8.12 --package conduit-combinators
{-# LANGUAGE ExtendedDefaultRules #-}
import Conduit

trans :: Monad m => ConduitM Int Int m ()
trans = do
    mapC (* 2)

main :: IO ()
main = runConduit $ yieldMany [1..10] .| trans .| mapM_C print

I get:

2 4 6 8 10 12 14 16 18 20

How can I modify trans so that it yields

1 3 6 10 15 21 28 36 45 55

instead?


Solution

  • scanlC, which is an "analog of scanl for lists", does almost what you want. I say "almost" because scanlC asks for and yields an initial "seed" value, which you don't need nor want (cf. the difference between scanl and scanl1). That being so, you will need to explicitly feed the first streamed value as the seed:

    trans :: Monad m => ConduitM Int Int m ()
    trans = await >>= maybe (return ()) (scanlC (+))
    

    (The -- clearly inferior -- alternative would be having trans = scanlC (+) 0 and using dropC 1 in the next step of the pipeline to get rid of the 0.)