3

有一个类型的生产者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 ())
4

1 回答 1

4

通常,您需要将 aProducer与 a组合在一起Consumer才能获得Effect可以运行的a runEffect。这不是你在这里得到的,但幸运的是,有更多的方法可以消除 aProxy而不仅仅是runEffect.

盘点我们所拥有的,这个组合以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只执行了第一个效果。懒惰多了!

于 2013-10-16T23:00:11.133 回答