连接生产者和管道以提取结果



有一个 Producer ByteString IO () 类型的生产者和一个 Pipe ByteString a IO () 类型的管道 我如何组成一个效果,这将导致运行时IO a

这是我最好的尝试:

{-# LANGUAGE ScopedTypeVariables #-}
import Pipes
import Data.ByteString
run :: forall a. IO a
run = runEffect $ 
  (undefined :: Producer ByteString IO ()) >-> (undefined :: Pipe ByteString a IO ())

它失败并显示以下内容:

Couldn't match type `Void' with `()'
Expected type: IO a
  Actual type: IO ()
In the expression:
  runEffect
  $ (undefined :: Producer ByteString IO ())
    >-> (undefined :: Pipe ByteString a IO ())
In an equation for `run':
    run
      = runEffect
        $ (undefined :: Producer ByteString IO ())
          >-> (undefined :: Pipe ByteString a IO ())

通常,您需要使用Consumer编写Producer才能获得可由runEffect运行的Effect。这不是你在这里得到的,但幸运的是,除了runEffect之外,还有更多方法可以消除Proxy

盘点一下我们所拥有的,这个组合最终会得到一个 Producer .

pipe :: Producer a IO ()
pipe = (undefined :: Producer ByteString IO ()) >-> (undefined :: Pipe ByteString a IO ()) 

Pipes.Prelude模块包含许多其他消除Producers的方法,例如Pipes.Prelude.last

last :: Monad m => Producer a m () -> m (Maybe a)

可能让a Pipes.Prelude.fold的最通用方法是使用

fold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Producer a m () -> m b

这就像runEffect,除了它减少了Producers到它们的基础Monad。因为这就是我们所拥有的,它会很好用。以下是我们如何实施Pipes.Prelude.head

slowHead = fold (res a -> res <> First (Just a)) mempty getFirst

尽管值得注意的是,slowHead消耗了整个Producer(从而执行了所有需要的效果),而Pipes.Prelude.head只执行了第一个效果。懒多了!

最新更新