あなたは間違いなくこれを使用したくありません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