如何在 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
) 而不是 APIEvent
s,那么
它不进行类型检查。
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
组合成 Consumer
个 Tuple
。所以现在你只需要一种方法将 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
可以胜任。
我想我开始了解协程生产者和消费者,但我最难将消费者和生产者以有用的方式放在一起。如果我有这个制作人 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
s,那么
它不进行类型检查。
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
组合成 Consumer
个 Tuple
。所以现在你只需要一种方法将 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
可以胜任。