2

私はpipes-4.0.0で作業しています。そのライブラリでは、パイプが行う下流へのyieldの数は、一般に、上流からの待機の数とは無関係です。

しかし、モナディック (>>=) を使用してこれらの種類のパイプをシーケンスできる一方で、各 await に対して 1 つだけの yield が実行されることを強制する制限付きパイプを構築したいとします。

双方向の場合、プロキシによってアップストリームから要求された各値は、返された値と一致することがわかりました。したがって、おそらく私が探しているのは、Proxy a' a () b m r -> Pipe a (Either b a') m r上流に向かう値を「反映」し、それらを下流への追加の利回りに変えるタイプの関数です。または、あまり一般的ではありませんが、Client a' a -> Pipe a a'. そのような機能は可能ですか?

4

2 に答える 2

4

あなたは間違いなくこれを使用したくありませんpipes。しかし、できることは、これを行う制限された型を定義し、その制限された型内ですべての接続とロジックを実行し、完了したらそれを に昇格させることPipeです。

必要な問題のタイプはこれで、次のようになりnetwire Wireます。

{-# LANGUAGE DeriveFunctor #-}

import Control.Monad.Trans.Free  -- from the 'free' package

data WireF a b x = Pass (a -> (b, x)) deriving (Functor)

type Wire a b = FreeT (WireF a b)

の観点から実装されているため、これは自動的にモナドおよびモナド変換子になりFreeTます。次に、この便利な操作を実装できます。

pass :: (Monad m) => (a -> b) -> Wire a b m ()
pass f = liftF $ Pass (\a -> (f a, ()))

...そして、モナド構文を使用してカスタム ワイヤを組み立てます。

example :: Wire Int Int IO ()
example = do
    pass (+ 1)
    lift $ putStrLn "Hi!"
    pass (* 2)

次に、この制限されたWireタイプとの接続が完了したら、次のように昇格できますPipe

promote :: (Monad m) => Wire a b m r -> Pipe a b m r
promote w = do
    x <- lift $ runFreeT w
    case x of
        Pure r -> return r
        Free (Pass f) -> do
            a <- await
            let (b, w') = f a
            yield b
            promote w'

ID とワイヤおよびワイヤ構成を定義できることに注意してください。

idWire :: (Monad m) => Wire a a m r
idWire = forever $ pass id

(>+>) :: (Monad m) => Wire a b m r -> Wire b c m r -> Wire a c m r
w1 >+> w2 = FreeT $ do
    x <- runFreeT w2
    case x of
        Pure       r   -> return (Pure r)
        Free (Pass f2) -> do
            y <- runFreeT w1
            case y of
                Pure       r   -> return (Pure r)
                Free (Pass f1) -> return $ Free $ Pass $ \a ->
                        let (b, w1') = f1 a
                            (c, w2') = f2 b
                        in  (c, w1' >+> w2')

私はそれらがaを形成していると確信していCategoryます:

idWire >+> w = w

w >+> idWire = w

(w1 >+> w2) >+> w3 = w1 >+> (w2 >+> w3)

promoteまた、次のファンクターの法則に従うと確信しています。

promote idWire = cat

promote (w1 >+> w2) = promote w1 >-> promote w2
于 2013-09-22T20:03:52.280 に答える
0

私の直感では、完全に不可能ではないにしても、これを行うのは非常に困難になるだろう. 複雑なループでいっぱいのプロデューサーとコンシューマーを書けるだけでなく、モナディック インターフェイスは、コンシューマーの制御フローがプロデューサーから取得した値に依存できるようにします。

consumer = do
  n <- await
  for i in 1..n do
     m <- await
     print m

プロデューサーの型で「これは N + 1 の数値を生成します。ここで、N は生成された最初の数値の値です」とエンコードするのは非常に困難です。


トピックに戻ると、パイプの基本モナディック インターフェイスの代わりに独自のコンビネータを使用すると、より良い可能性があると思います。たとえば、ブーメラン Web ルートライブラリは一連のコンビネータを使用して、(ルート -> URL) 変換を実行するコードと (URL -> ルート) 変換を実行するコードを同時に作成し、互換性と逆を保証します。お互いの。

于 2013-09-22T17:54:20.560 に答える