haskell - 如果MonadPlus是"generator" 类,那么"consumer" 类是什么?

  显示原文与译文双语对照的内容
0 0

A Pipe可以分为两部分: 生成器部分( yield) 和消费者部分( await) 。

如果你有一个 Pipe只有使用它的生成器家,而且只返回 ()( 或不返回),则可以将其表示为" ListTdone right " 。 你会发现, MonadPlus可用于表示任何像ListT的理想选择。

http://www .reddit .com/r/haskell/comments/2bpsh7/a_simple_monadic_stream_library/cj7sqtwcontext=3

因此我的问题是这样: 是否可通过双ListT和MonadPlus代表使用者Pipes的一部分?

要求:

  • 一个管的人都没有使用 yield,并且仅返回 ()( 或不返回),但不使用 await可表示为这个" 双ListT " 。
  • 将" 双ListT " 可归纳为的" 双MonadPlus "
时间:原作者:4个回答

0 0

我想答案是不要要延伸dualize " " generator type类就像",而是使用一个简单的 Category实例等效于 await/ (>~)一类 pipes.

不幸的是,没有办法安排类型变量来把这个满足这三种类型的类( MonadPlus, MonadTrans以及 Category),因此需要定义一个新的类型的类:

{-# 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)

然后,你可以实现这两种 Consumers 和 Pipes 后,此附加类型类:

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)
-}

最难的部分就是确定如何执行此操作,而不添加新的class类型 base. 我想和她重新使用原来的 Categorytype类,如果可能的话,可能是这样 await(>~)只要是你喜欢的类型包装在一个newtype的函数,请使用 Category实例,再展开该实例,但我仍在商谈制订的详细说明应该怎么做。

编辑: 我找到了解决方案。 只要定义下列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)

那么任何库就能实现 Category实例中包装它们的类型的 Consumernewtype 。

那么你就可以得到一个约束,这样无论什么时候使用 await(>~):

cat :: (MonadPlus (t a m), Category (Consumer t m)) => t a m a
cat = await `mplus` cat
原作者:
0 0

这只是一个片段的答案,它当前转ganglia监视Gabriel是最新回答。 现在,这个应答停止小与有趣的一点,那就是: >->是Tekmo方面的替代方法 ListT方面 MonadTransMonadPlus.

让我们把管道库为教学。 管道装置重采用以下类型:

data Proxy a' a b' b m r
    = Request a' (a  -> Proxy a' a b' b m r )
    | Respond b  (b' -> Proxy a' a b' b m r )
    | M          (m    (Proxy a' a b' b m r))
    | Pure    r

响应类别

关联的类别管道 yieldrespond类别。 标识 respond类别是 respond和组合运算符 />/,由两种日程安排。 让我们来看看响应,事关 yield.

respond被定义为

respond :: Monad m => a -> Proxy x' x a' a m a'
respond a = Respond a Pure

yield很简单, respond,只是抛出뿪某些部分管道要丢掉。

yield :: (Monad m) => a -> Producer' a m ()
yield = respond

我们将忽略稍微多态类型 Producer',而是考虑 Producer:

type Producer b = Proxy X () () b

Producers 只能 yield

X是的void类型无人居住。 如果我们替换这些类型在 Proxy说,是我们

data Proxy X () () b m r
    = Request X (() -> Proxy X () () b m r )
    | Respond b (() -> Proxy X () () b m r )
    | M         (m    (Proxy X () () b m r))
    | Pure    r

这简化了,实际上

type Producer b m r 
    = Respond b (   Producer b m r )
    | M         (m (Producer b m r))
    | Pure    r

在管道中, return = Pure. 我们能限制你的约束,因为它仅返回过 ()通过替换变量的类型将作为 Pure是参数与 ().

type Generator m b = Producer b m ()
    = Respond b  (   Generator m b )
    | M          (m (Generator m b))
    | Pure

在" ListT立刻完成的" respond分类本质上是

return = yield
>>=    = //>   = for
lift m = M (m >>= yield)

MonadPlus这将是实例。

mzero = Pure
mplus = >>

请求类别

在管道的双 respond接收日志 request与之关联的类别, await. request是的身份 request类别,及其的作文 >,由两种折叠。 首先,我们将看到 await关联起来的 request.

request本质上是相同 respond.

request :: Monad m => a' -> Proxy a' a y' y m a
request a' = Request a' Pure

await按照定义, request,但要求我们不发送任何数据吧,除了那个球童被打中他。

await :: (Monad m) => Consumer' a m a
await = request ()

我们将忽略稍微多态类型 Consumer',而是考虑 Consumer:

type Consumer a = Proxy () a () X

Consumers 只能 await

如果我们替换这些类型在 Proxy说,是我们

data Proxy () a () X m r
    = Request () (a  -> Proxy () a () X m r )
    | Respond X  (() -> Proxy () a () X m r )
    | M          (m    (Proxy () a () X m r))
    | Pure    r

这简化了,实际上

type Consumer a m r
    = Request   (a -> Consumer a m r )
    | M         (m   (Consumer a m r))
    | Pure    r

当我们要求它不返回任何操作, (),就可以得到如下,我也将调用一个 Iteratee为了避免混淆猛打' Consumer.

type Iteratee m a
    = Request (a -> Iteratee m a )
    | M       (m   (Iteratee m a))
    | Pure

我们会注意到的第一件事情是,我们没有任何其他编写任何有意义的方式 return :: a -> Iteratee m a,所以我们没有 Monad. 我们需要先介绍我们 GeneratorIteratee交互图结果是什么。

连接管道

管道被连接起来。 >->

(>->)
    :: Monad m
    => Proxy a' a () b m r
    -> Proxy () b c' c m r
    -> Proxy a' a c' c m r
p1 >-> p2 = (() -> p1) +>> p2
(+>>)
    :: Monad m
    => (b' -> Proxy a' a b' b m r)
    ->        Proxy b' b c' c m r
    ->        Proxy a' a c' c m r
fb' +>> p = case p of
    Request b' fb  -> fb' b' >>~ fb
    Respond c  fc' -> Respond c (c' -> fb' +>> fc' c')
    M          m   -> M (m >>= p' -> return (fb' +>> p'))
    Pure       r   -> Pure r
(>>~)
    :: Monad m
    =>       Proxy a' a b' b m r
    -- ^
    -> (b -> Proxy b' b c' c m r)
    -- ^
    ->       Proxy a' a c' c m r
    -- ^
p >>~ fb = case p of
    Request a' fa  -> Request a' (a -> fa a >>~ fb)
    Respond b  fb' -> fb' +>> fb b
    M          m   -> M (m >>= p' -> return (p' >>~ fb))
    Pure       r   -> Pure r

如果我们将此简化为只 GeneratorIteratee就可以得到如下,这阴谋要删除每一处 requestrespond.

(>->)
    :: Monad m
    => Generator m b
    -> Iteratee  m b
    -> Proxy X () () X m ()
p1 >-> p2 = case p2 of
    Request fb -> p1 >>~ fb
    M       m  -> M (m >>= p' -> return (p1 >-> p'))
    Pure       -> Pure
(>>~)
    :: Monad m
    => Generator m b
    -> (b -> Iteratee m b)
    -> Proxy X () () X m ()
p >>~ fb = case p of
    Respond b  fb' -> fb' >-> fb b
    M          m   -> M (m >>= p' -> return (p' >>~ fb))
    Pure           -> Pure

这是执行到 m ()通过 runEffect,运行它只是每 M,直到遇到一个 Pure.

下一站去哪里。。。

下一步是重写 >->方面 MonadTransMonadPlusGenerator而且你可以看到要求的。 Iteratee. 之后我们会找到一个很好的界面 Iteratee. 我预感中的是我们没有找到它 base.

connection Generators Iteratees

tekmo的替代方法 ListT方面 MonadTransMonadPlus基于以下,据我所知,撤下观察:

  • return在transformer中可以看作是 yielding结果为transformer
  • mzero为空操作,可以被看作是指示间隔结束的列表
  • mplus允许我们连接两个列表的第一个共同行动,要求结果不会被放弃

类型 Generator然后会类似

type Generator2 m a = forall t. (MonadTrans t, MonadPlus t m) => t m a

通过连接一个 Generator方面 MonadTransMonadPlusIteratee在其他一些方面,资金来源外,我们希望发现什么的双 MonadTransMonadPlus来吧? 因为我们还没有这些未知的所有事物的名称,我只好把他们都加上前缀 Co.

假设某种对称性,我们期望的类型为 Iteratee要类似

type Iteratee2 m a = forall t. (CoMonadTrans t, CoMonadPlus t m) => t m a

为thing的类型组合一个 Generator在任期 MonadTransMonadPlusIteratee在某些方面,如资金来源接口将

connect
    :: (Monad m)
    => Generator2 m a
    -> Iteratee2  m a
    -> m ()

我们将提供一个定义,寄希望于管道图书馆偷它 >->.

connect g i = runEffect (enumerate g >-> coenumerate i)

enumerate这里来自管道'适当 ListTtransformer :

newtype ListT m a = Select { enumerate :: Producer a m () }

下面我们假设某种对称性的,这个必须说,可能存在的类型:

newtype CoListT m a = CoSelect { coenumerate :: Consumer a m () }

故人已逝现在的问题是搞清楚类 CoListT重新创建的可以提供实例构造消费者的行为。

原作者:
...