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 的对偶”
有帮助吗?

解决方案

我认为答案不是对“类似生成器”的类型类进行二元化,而是用一个简单的方法来扩展它 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)

然后你可以同时实现 ConsumerPipe一旦你有了这个额外的类型类:

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

困难的部分是弄清楚如何在不添加新类型类的情况下做到这一点 base. 。我更愿意重复使用原来的 Category 如果可能的话,键入类,可能有 await(>~) 只是将您的类型包装在新类型中的函数,使用 Category 实例,然后打开它,但我仍在研究如何做到这一点的细节。

编辑:我找到了解决方案。只需定义以下新类型:

{-# 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 其类型的实例包含在 Consumer 新类型。

那么每当你使用时你都会得到这样的约束 await 或者 (>~):

cat :: (MonadPlus (t a m), Category (Consumer t m)) => t a m a
cat = await `mplus` cat
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top