如何在 PureScript 中将多个协程消费者与单个生产者结合起来?

How do I join multiple coroutine Consumers with a single Producer in PureScript?

我想我开始了解协程生产者和消费者,但我最难将消费者和生产者以有用的方式放在一起。如果我有这个制作人 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"
  )

我如何将它连接到两个进行系统日志记录和基本操作的消费者 输出,例如

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)

我试过使用 joinConsumers,但这会创建一个消费者 (Tuple APIEvent APIEvent) 而不是 APIEvents,那么 它不进行类型检查。

main = launchAff $ do
  v <- runProcess $
        (joinConsumers logFailures showOutput)
        `pullFrom` (loop getPeerID)
  log $ "Process result: " <> (show v)

编辑:

这就是我的结局。

main = launchAff $ do
  v <- runProcess $
    transformConsumer
      (forever $ transform (\i -> Tuple i i))
      (joinConsumers logFailures showOutput)
    `pullFrom` (loop getID)
  log $ "Process result: " <> (show v)

输出...

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"

如您所见,您可以使用 joinConsumers 将两个 Consumer 组合成 ConsumerTuple。所以现在你只需要一种方法将 Consumer of Tuple a a 更改为常规 Consumer of a.

您可以使用 transformConsumer 函数执行此操作,该函数使用 Transformer:

转换 Consumer
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

但是如何在那里创建Transformer呢?那么,您可以使用 transform 函数从常规函数创建一个:

transform
  :: forall m i o
   . Monad m
  => (i -> o)
  -> Transformer i o m Unit

您需要的函数类型是 a -> Tuple a a,因此 \a -> Tuple a a 可以胜任。