Kevin Meredith
Kevin Meredith

Reputation: 41909

Understanding `conduit` Output

Using Conduit, given:

Prelude> :t (yieldMany [1..10] .| mapC show .| mapC print .| sinkList)
(yieldMany [1..10] .| mapC show .| mapC print .| sinkList)
  :: Monad m => ConduitM a c m [IO ()]

Why doesn't any output get logged?

Prelude> runConduit $ yieldMany [1..10] .| mapC show .| mapC print .| sinkList
Prelude>

My expectation was that, for a stream of [1..10], each element's String, i.e. show, value would be printed.

Please explain this output.

Upvotes: 2

Views: 195

Answers (1)

Zeta
Zeta

Reputation: 105876

The result of the conduit is a list of IO () in a monad, not a single IO ():

Prelude Conduit> :t runConduit $ yieldMany [1..10] .| mapC show .| mapC print .| sinkList
runConduit $ yieldMany [1..10] .| mapC show .| mapC print .| sinkList
  :: Monad m => m [IO ()]

Even if you set m to IO, you end up with IO [IO ()] as result, which doesn't get shown because [IO ()] does not have a Show instance. You can fix that if you add >>= sequence_:

(runConduit $ yieldMany [1..10] .| mapC show .| mapC print .| sinkList) >>= sequence_

However, the real problem is that you use mapC print instead of mapMC print:

Prelude Conduit> :t mapC
mapC :: Monad m => (a -> b) -> Conduit a m b
Prelude Conduit> :t mapMC
mapMC :: Monad m => (a -> m b) -> Conduit a m b

If you use mapC print, you end up with Conduit a m (IO ()). If you use mapMC print, you end up with Conduit a IO (). The latter sets m to IO, the first does not.

So use the correct combinator for monadic functions:

runConduit $ yieldMany [1..10] .| mapC show .| mapMC print .| sinkNull
--                                                ^

Also, check the type of it in GHCi if you don't get the expected result.

Upvotes: 6

Related Questions