如果MonadPlus是"生成器"类,那么什么是"消费者"类?

Dan*_*ton 13 haskell category-theory iterate haskell-pipes

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

如果你有一个Pipe只使用它的生成器一半,并且只返回()(或永不返回),那么它可以表示为" ListT完成权限".事实证明,MonadPlus它可以用来代表像ListT-done-right这样的东西.

http://www.reddit.com/r/haskell/comments/2bpsh7/a_simple_monadic_stream_library/cj7sqtw?context=3

所以我的问题是:对于Pipes的消费者部分,ListT和MonadPlus是否存在双重性?

要求:

  • 从不使用yield,只返回()(或永不返回)但确实使用的管道await可以表示为"对ListT"的双重.
  • "对ListT的双重"可以推广到"MonadPlus的双重"

Gab*_*lez 9

我认为答案不是将"类似生成器"的类类型二元化,而是使用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
Run Code Online (Sandbox Code Playgroud)

此类型的法律是类别法:

await >~ f = f

f >~ await = f

(f >~ g) >~ h = f >~ (g >~ h)
Run Code Online (Sandbox Code Playgroud)

然后Consumer,Pipe一旦有了这个额外的类型类,你就可以实现s和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)
-}
Run Code Online (Sandbox Code Playgroud)

困难的部分是在不添加新类型的情况下弄清楚如何做到这一点base.我宁愿重新使用原来的Category,如果可能的类型类,可能有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)
Run Code Online (Sandbox Code Playgroud)

然后任何库都可Category以为Consumernewtype中包含的类型实现一个实例.

然后你会在任何时候使用await或得到这样的约束(>~):

cat :: (MonadPlus (t a m), Category (Consumer t m)) => t a m a
cat = await `mplus` cat
Run Code Online (Sandbox Code Playgroud)