如何在PureScript中使用单个Producer加入多个协程消费者?

时间:2017-02-28 21:46:12

标签: coroutine purescript

我认为我开始了解Coroutine的制作人和消费者,但我最难以有用的方式将消费者和产品放在一起。如果我有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)而不仅仅是APIEvent,所以那么 它没有打字检查。

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"

1 个答案:

答案 0 :(得分:4)

正如您所注意到的,您可以使用joinConsumers将两个Consumer合并到ConsumerTuple中。现在,您只需要一种方法将Consumer Tuple a a更改为常规Consumer a

您可以使用transformConsumer功能执行此操作,该功能使用Consumer转换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

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

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

您需要的功能类型为a -> Tuple a a,因此\a -> Tuple a a可以完成此任务。