I'm think I'm starting to understand Coroutine producers and consumers, but I'm having the hardest time putting consumers and produces together in useful ways. If I have this producer of APIEvent
...
type ID = String
data APIEvent
= Connecting
| Fail String
| Success String
derive instance gAPIEvent :: Generic APIEvent
instance showPeerEvent :: Show APIEvent where show = gShow
getID :: Producer APIEvent (Aff (avar :: AVAR, console :: CONSOLE, random :: RANDOM)) (Maybe ID)
getID = produceAff (\emit -> do
i <- liftEff $ randomInt 0 10
if i < 9
then do
-- If producer was called with `loop`, the
-- producer will restart.
emit $ Left $ Fail "Failure to get id."
emit $ Right Nothing
else do
emit $ Left $ Success "id"
emit $ Right $ Just "id"
)
How would I connect it to two consumers that do system logging and basic output, e.g.
logFailures :: Consumer APIEvent (Aff (avar :: AVAR, console :: CONSOLE, random :: RANDOM)) ID
logFailures = forever $ do
event <- await
lift $ do
case event of
(Fail message) -> log $ "LOG: " <> message
showOutput :: Consumer APIEvent (Aff (avar :: AVAR, console :: CONSOLE, random :: RANDOM)) ID
showOutput = forever $ do
event <- await
lift $ do
log $ "STDOUT: " <> (show event)
I've tried using joinConsumers
, but that creates a consumer of
(Tuple APIEvent APIEvent
) instead of just APIEvent
s, so then
it doesn't type check.
main = launchAff $ do
v <- runProcess $
(joinConsumers logFailures showOutput)
`pullFrom` (loop getPeerID)
log $ "Process result: " <> (show v)
Edit:
This is what I ended up with.
main = launchAff $ do
v <- runProcess $
transformConsumer
(forever $ transform (\i -> Tuple i i))
(joinConsumers logFailures showOutput)
`pullFrom` (loop getID)
log $ "Process result: " <> (show v)
Outputs...
LOG: Failure to get id.
STDOUT: Test.SO.Fail "Failure to get id."
LOG: Failure to get id.
STDOUT: Test.SO.Fail "Failure to get id."
STDOUT: Test.SO.Success "id"
Process result: "id"
As you've noticed, you can use joinConsumers
to combine two Consumer
s into a Consumer
of Tuple
s. So now you just need a way to change a Consumer
of Tuple a a
into a regular Consumer
of a
.
You can do this by using the transformConsumer
function, which transforms a Consumer
using a Transformer
:
transformConsumer
:: forall i o f m a
. (MonadRec m, Parallel f m)
=> Transformer i o m a
-> Consumer o m a
-> Consumer i m a
But how to create the Transformer
there? Well, you can create one from a regular function using the transform
function:
transform
:: forall m i o
. Monad m
=> (i -> o)
-> Transformer i o m Unit
The function type you need is a -> Tuple a a
, so \a -> Tuple a a
will do the job.