MonAdplusが "Generator"クラスの場合は、「消費者」クラスとは何ですか?
-
26-12-2019 - |
質問
Pipe
は、 Generator パート(yield
)と Consumer Part(await
)との2つの部分に分割できます。
Generator Hareのみを使用しているPipe
を使用している場合は、()
(または未返信)のみを返す場合は、「ListT
Donegred」として表すことができます。 MonadPlus
を使用してListt-Done-Rightのようなものを表すことができます。
だから私の質問はこれです:パイプの消費者部分のためのListtとMonadplusには、Listtへの二重がありますか?
要件:
-
yield
を使用しないパイプで、()
(または未返信)のみを返しますが、この「デュアルからListt」として表示できます。 - 「派閥からListt」は、「Monadplusのデュアル」に一般化することができます
解決
答えは「発電機のような」タイプクラスを締め付けることではなく、Category
のawait
/ (>~)
カテゴリと同等の単純なpipes
インスタンスで拡張することです。
残念ながら、これを3つの型クラス(MonadPlus
、GeneraCodeTagCode、およびMonadTrans
)を満たすようにするようにタイプ変数を配置する方法はありませんので、新しい型クラスを定義します。
{-# LANGUAGE KindSignatures #-}
import Control.Monad
import Control.Monad.Trans.Class
class Consumer (t :: * -> (* -> *) -> * -> *) where
await :: t a m a
(>~) :: t a m b -> t b m c -> t a m c
.
このタイプのクラスの法律はカテゴリー法則です:
await >~ f = f
f >~ await = f
(f >~ g) >~ h = f >~ (g >~ h)
.
この追加タイプクラスを使用したら、Category
sとConsumer
sの両方を実装できます。
printer :: (Show a, Monad (t a IO), MonadTrans (t a), Consumer t) => t a IO r
printer = do
a <- await
lift (print a)
printer
{-
printer :: Show a => Consumer a IO r
printer = do
a <- await
lift (print a)
printer
-}
cat :: (MonadPlus (t a m), Consumer t) => t a m a
cat = await `mplus` cat
{-
cat :: Monad m => Pipe a a m r
cat = do
a <- await
yield a
cat
-}
debug :: (Show a, MonadPlus (t a IO), MonadTrans (t a), Consumer t) => t a IO a
debug = do
a <- await
lift (print a)
return a `mplus` debug
{-
debug :: Show a => Pipe a a IO r
debug = do
a <- await
lift (print a)
yield a
debug
-}
taker :: (Consumer t, MonadPlus (t a m)) => Int -> t a m a
taker 0 = mzero
taker n = do
a <- await
return a `mplus` taker (n - 1)
{-
taker :: Monad m => Int -> Pipe a a m ()
taker 0 = return ()
taker n = do
a <- await
yield a
taker (n - 1)
-}
.
ハード部分は、Pipe
に新しい型クラスを追加することなくこれを行う方法を考え出すことです。可能であれば、NewTypeでタイプをラップする関数だけでbase
とCategory
を使用しているだけで、await
インスタンスを使用してから、それを解除しています。それをする方法。
編集:解決策を見つけました。次のnewtypeを定義するだけです。
{-# LANGUAGE KindSignatures, FlexibleContexts #-}
import Control.Category
import Prelude hiding ((.), id)
newtype Consumer t m a b = Consumer { unConsumer :: t a m b }
await :: Category (Consumer t m) => t a m a
await = unConsumer id
(>~) :: Category (Consumer t m) => t a m b -> t b m c -> t a m c
f >~ g = unConsumer (Consumer f >>> Consumer g)
.
その後、任意のライブラリは、(>~)
NewTypeでラップされたそれらのタイプのCategory
インスタンスを実装するだけです。
そのような制約は、Category
またはConsumer
を使用したときに、このような制約を受けるでしょう:
cat :: (MonadPlus (t a m), Category (Consumer t m)) => t a m a
cat = await `mplus` cat
.