甚至超过pipes-parse你很可能想看看pipes-group . 特别是,让我们检查一下这个功能
-- this type is slightly specialized
chunksOf
:: Monad m =>
Int ->
Lens' (Producer a m x) (FreeT (Producer a m) m x)
Lens' 位可能很可怕,但可以快速消除:它表明我们可以将 Producer a m x 转换为 FreeT (Producer a m) m x [0]
import Control.Lens (view)
chunkIt :: Monad m => Int -> Producer a m x -> FreeT (Producer a m) m x
chunkIt n = view (chunksOf n)
所以现在我们必须弄清楚如何处理 FreeT 位 . 特别是,我们想要深入研究free包并拉出函数 iterT
iterT
:: (Functor f, Monad m) =>
(f (m a) -> m a) ->
(FreeT f m a -> m a)
这个函数 iterT ,让我们一次 FreeT FreeT 一个"step" . 为了理解这一点,我们首先将 iterT 的类型专门用 Producer a m 替换 f
runChunk :: Monad m =>
(Producer a m (m x) -> m x) ->
(FreeT (Producer a m) m x -> m x)
runChunk = iterT
特别是,只要我们告诉它如何将 Producer a m (m x) 转换为 m -action,"run"就可以 FreeT 充满 Producer . 这可能开始看起来更熟悉了 . 当我们定义 runChunk 的第一个参数时,我们只需要执行一个 Producer ,在这种情况下,它将只有选定数量的元素 .
但是有效的返回值是什么? m x ?这是"continuation",例如在当前版本之后出现的所有块我们都假设我们有 Producer 的 Char 并且我们想在3个字符之后打印和换行
main :: IO ()
main = flip runChunk (chunkIt 3 input) $ \p -> _
此时 _ 孔在 p :: Producer Char IO (IO ()) 类型的上下文中具有 IO () 和 p 类型 . 我们可以使用 for 来使用此管道,收集它的返回类型(再次是延续),发出换行符,然后运行continuation .
input :: Monad m => Producer Char m ()
input = each "abcdefghijklmnopqrstuvwxyz"
main :: IO ()
main = flip runChunk (chunkIt 3 input) $ \p -> do
cont
putChar '\n'
cont
这表现完全符合要求
λ> main
abc
def
ghi
jkl
mno
pqr
stu
vwx
yz
要清楚,虽然我做了一些阐述,但是一旦你看到所有部分如何组合在一起,这是相当简单的代码 . 这是整个列表:
input :: Monad m => Producer Char m ()
input = each "abcdefghijklmnopqrstuvwxyz"
main :: IO ()
main = flip iterT (input ^. chunksOf 3) $ \p -> do
cont do
lift (putChar c)
putChar '\n'
cont
[0]还有点多,但现在已足够了 .