Loops 如果MonadPlus是;发电机“;类,那么“类”是什么;“消费者”;上课?
Loops 如果MonadPlus是;发电机“;类,那么“类”是什么;“消费者”;上课?,loops,haskell,category-theory,haskell-pipes,monadplus,Loops,Haskell,Category Theory,Haskell Pipes,Monadplus,管道可以分为两部分:发电机部分(产量)和用户部分(等待) 如果有一个管道只使用它的生成器的一半,并且只返回()(或从不返回),那么它可以表示为“列表正确完成”。事实证明,MonadPlus可以用来表示像ListDone right这样的任何东西 请注意,您可以只使用transformers依赖项构建任何ListT(而不仅仅是管道中的一个)。例如,下面是如何实现Pipes.Prelude.stdinLn的ListT模拟: -- stdinLn :: ListT IO String stdinLn
管道可以分为两部分:发电机部分(产量
)和用户部分(等待
)
如果有一个管道
只使用它的生成器的一半,并且只返回()
(或从不返回),那么它可以表示为“列表
正确完成”。事实证明,MonadPlus
可以用来表示像ListDone right这样的任何东西
请注意,您可以只使用transformers依赖项构建任何ListT
(而不仅仅是管道中的一个)。例如,下面是如何实现Pipes.Prelude.stdinLn的ListT
模拟:
-- stdinLn :: ListT IO String
stdinLn :: (MonadTrans t, MonadPlus (t IO)) => t IO String
stdinLn = do
eof <- lift isEOF
if eof
then mzero
else do
str <- lift getLine
return str `mplus` stdinLn
--stdinLn::ListT IO字符串
stdinLn::(MonadTrans t,MonadPlus(tio))=>tio字符串
stdinLn=do
eof我认为答案不是将“generator-like”类型类双重化,而是使用一个简单的类别
实例来扩展它,该实例相当于管道的/(>~)
类别
不幸的是,无法安排类型变量使其满足所有三个类型类(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
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)
-}
此类型类别的规则为类别规则:
await >~ f = f
f >~ await = f
(f >~ g) >~ h = f >~ (g >~ h)
然后,一旦您有了这个额外的类型类,您就可以同时实现Consumer
s和Pipe
s:
{-# 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
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)
-}
然后,任何库都可以为包装在使用者
newtype中的类型实现一个类别
实例
然后,无论何时使用wait
或(>~)
,您都会得到这样的约束:
我会认为这类似于FoldM
,但我没有想太多。也许是吧?这不是我想要的,但我确实想提到类别(消费者t m)
的想法非常酷。