purescript-coroutinesにaconnect
と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)
さて、これにはちょっとした驚きがあります...でも、すぐにそれに行きます。
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が出力され、すぐに終了します。
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加