二つの考えの間には強いつながりがあるように私には思えます。私の推測では、Iteratees で任意のグラフを表現する方法があれば、FRP は Iteratees の観点から実装できると思います。しかし、私の知る限り、彼らはチェーンのような構造しかサポートしていません。
誰かがこれに光を当てることができますか?
二つの考えの間には強いつながりがあるように私には思えます。私の推測では、Iteratees で任意のグラフを表現する方法があれば、FRP は Iteratees の観点から実装できると思います。しかし、私の知る限り、彼らはチェーンのような構造しかサポートしていません。
誰かがこれに光を当てることができますか?
それは逆です。AFRP とストリーム処理の間には強いつながりがあります。実際、AFRPはストリーム処理の形式であり、イディオムを使用して、パイプに非常に似たものを実装できます。
data Pipe m a b =
Pipe {
cleanup :: m (),
feed :: [a] -> m (Maybe [b], Pipe m a b)
}
これは、Netwire に見られるワイヤ カテゴリの拡張です。入力の次のチャンクを受け取り、生成を停止すると Nothing を返します。これを使用すると、ファイル リーダーは次のタイプになります。
readFile :: (MonadIO m) => FilePath -> Pipe m a ByteString
Pipe は applicative functor のファミリーであるため、単純な関数をストリーム要素に適用するには、 fmapを使用するだけです:
fmap (B.map toUpper) . readFile
便宜上、profunctor のファミリーでもあります。
最も興味深い特徴は、これが代替ファンクターのファミリーであることです。これにより、ストリームをルーティングし、複数のストリーム プロセッサがあきらめる前に「試行」できるようになります。これは、最適化のためにいくつかの静的情報を使用することさえできる本格的な解析ライブラリに拡張できます。
ストリーム プロセッサを使用して、限定された形式の FRP を実装できます。たとえば、pipes
ライブラリを使用して、イベントのソースを定義できます。
mouseCoordinates :: (Proxy p) => () -> Producer p MouseCoord IO r
... 同様に、マウス座標を取得してキャンバス上のカーソルを更新するグラフィカル ハンドラーを定義することもできます。
coordHandler :: (Proxy p) => () -> Consumer p MouseCoord IO r
次に、コンポジションを使用してマウス イベントをハンドラーに接続します。
>>> runProxy $ mouseCoordinates >-> coordHandler
そして、期待どおりに動作します。
あなたが言ったように、これはステージの単一チェーンではうまく機能しますが、より任意のトポロジーではどうでしょうか? の中心的なProxy
型pipes
はモナド変換子であるため、プロキシモナド変換子をそれらの上にネストするだけで、任意のトポロジをモデル化できることがわかります。たとえば、2 つの入力ストリームを圧縮する方法は次のとおりです。
zipD
:: (Monad m, Proxy p1, Proxy p2, Proxy p3)
=> () -> Consumer p1 a (Consumer p2 b (Producer p3 (a, b) m)) r
zipD () = runIdentityP $ hoist (runIdentityP . hoist runIdentityP) $ forever $ do
a <- request () -- Request from the outer Consumer
b <- lift $ request () -- Request from the inner consumer
lift $ lift $ respond (a, b) -- Respond to the Producer
これは、カリー化された関数のように動作します。各入力に順次部分的に適用し、完全に適用されたときに実行できます。
-- 1st application
p1 = runProxyK $ zipD <-< fromListS [1..]
-- 2nd application
p2 = runProxyK $ p2 <-< fromListS [4..6]
-- 3rd application
p3 = runProxy $ printD <-< p3
期待どおりに実行されます。
>>> p3
(1, 4)
(2, 5)
(3, 6)
このトリックは、あらゆるトポロジーに一般化されます。これについての詳細は、Control.Proxy.Tutorialの「ブランチ、zip、およびマージ」セクションにあります。特に、fork
ストリームを 2 つの出力に分割できる例として使用するコンビネータを確認する必要があります。