我不确定我理解purescript-coroutines中有connect
和pullFrom
功能的原因,以及何时使用它们。看看这些类型,似乎他们已经习惯了改变沟通的方向" (我不确定这是不是正确的思考方式)。
pullFrom :: forall o m a. MonadRec m => Consumer o m a -> Producer o m a -> Process m a
connect :: forall o f m a. (MonadRec m, Parallel f m) => Producer o m a -> Consumer o m a -> Process m a
所以如果我有消费者和制片人......
consumer :: forall e a. (Show a) => Consumer a (Eff (console :: CONSOLE | e)) Unit
consumer = forever do
s <- await
lift (log $ show s)
numberProducer :: forall m. (Monad m) => Producer Int m Unit
numberProducer = go 0
where
go i = do emit i
go (i + 1)
对我来说,消费者可以从生产者那里取出来是有意义的,如果我运行它,我可以看到数字显示......
main = do
runProcess (pullFrom consumer numberProducer)
但如果我connect
生产者是消费者,它似乎什么都不做。我假设当你将生产者连接到消费者时,信号传递的方向与pullFrom
相反,但我不确定这个想法是否正确。
main = do
runProcess (connect producer consumer)
答案 0 :(得分:4)
嗯,这里有一个有趣的小惊喜......我会在一分钟内来到这里。
pullFrom
被引入,以便消费者在形成流程时“负责” - 只要消费者处于打开状态(等待输入),该流程就会存在。
connect
就会运行,并且只有当他们都完成时才会终止。
为实现此目的,connect
具有Parallel
类约束,因为创建的进程依赖于使用者和生成者 - pullFrom
不需要这样,因为该进程仅依赖于consumer
。
这就是“有趣”惊喜的来源 - 让我困惑了一分钟。 Eff
不是Parallel
...那么您的代码如何运作?这是因为它推断main
的这种类型:
main :: forall t. (Parallel t (Eff (console :: CONSOLE))) => Eff (console :: CONSOLE) Unit
因此在程序运行时没有任何反应,因为在JS中,main
期望为Parallel
约束传递字典,然后评估Eff
。生成的对main的调用仅为Main.main();
,因此它实际上从未评估Eff
,因为它需要Main.main(impossibleParallelDictionary)();
。
尝试将此类型添加到main
:
main :: Eff (console :: CONSOLE) Unit
你会发现它不再打字了。
虽然您可以使用Aff
,但Aff
connect
和pullFrom
之间的区别对于此示例无法区分:
import Prelude
import Control.Coroutine (Consumer, Producer, await, connect, emit, runProcess)
import Control.Monad.Aff (Aff, launchAff)
import Control.Monad.Aff.Console (CONSOLE, log)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Control.Monad.Rec.Class (forever)
import Control.Monad.Trans.Class (lift)
consumer :: forall e a. (Show a) => Consumer a (Aff (console :: CONSOLE | e)) Unit
consumer = forever do
s <- await
lift (log $ show s)
numberProducer :: forall m. (Monad m) => Producer Int m Unit
numberProducer = go 0
where
go i = do emit i
go (i + 1)
main :: Eff (err :: EXCEPTION, console :: CONSOLE) Unit
main = void $ launchAff $ runProcess (connect numberProducer consumer)
如果我们稍微修改一下这个例子,我们可以看到差异的例子:
import Prelude
import Control.Coroutine (Consumer, Producer, await, emit, connect, runProcess)
import Control.Monad.Aff (Aff, launchAff, later')
import Control.Monad.Aff.Console (CONSOLE, log)
import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Exception (EXCEPTION)
import Control.Monad.Trans.Class (lift)
consumer :: forall e a. (Show a) => Consumer a (Aff (console :: CONSOLE | e)) Unit
consumer = do
s <- await
lift (log $ show s)
numberProducer :: forall eff. Producer Int (Aff eff) Unit
numberProducer = do
emit 0
lift $ later' 10000 $ pure unit
main :: Eff (err :: EXCEPTION, console :: CONSOLE) Unit
main = void $ launchAff $ runProcess (connect numberProducer consumer)
这样,程序将打印0,等待10秒,然后退出。如果您为connect numberProducer consumer
切换consumer `pullFrom` numberProducer
,程序将打印0并立即退出。