已经问过how to run a Consumer
inside a Pipe
的问题,但是之后提供的答案需要Consumer'
多态类型同义词:
{-# LANGUAGE RankNTypes #-}
import Pipes
toPipe :: Monad m => Consumer' i m o -> Pipe i o m ()
toPipe consumer = consumer >>= yield
现在,我遇到的问题是在Pipes.Vector
中,toVector
使用单形Consumer
同义词:
toVector :: (PrimMonad m, MVector (Mutable v) e) => Consumer e (ToVector v e m) r
因此,在这种情况下,该答案的toPipe
函数将不起作用:
{-# LANGUAGE RankNTypes #-}
module VectorPipe where
import Control.Monad.Primitive (PrimMonad)
import qualified Data.Vector.Generic as G
import Pipes
import Pipes.Vector
toPipe :: Monad m => Consumer' i m o -> Pipe i o m ()
toPipe consumer = consumer >>= yield
vectorPipe :: (PrimMonad m, G.Vector v a) => Pipe a (v a) m ()
vectorPipe = toPipe (runToVectorP toVector)
{-
VectorPipe.hs:13:35-42: Could not deduce (y' ~ ()) …
from the context (PrimMonad m, G.Vector v a)
bound by the type signature for
vectorPipe :: (PrimMonad m, G.Vector v a) => Pipe a (v a) m ()
at /Users/casillas/GitHub/tau-sigma/VectorPipe.hs:12:15-62
‘y'’ is a rigid type variable bound by
a type expected by the context: Proxy () a y' y m (v a)
at /Users/casillas/GitHub/tau-sigma/VectorPipe.hs:13:14
Expected type: Proxy () a y' y (ToVector v a m) r0
Actual type: Consumer a (ToVector v a m) r0
In the first argument of ‘runToVectorP’, namely ‘toVector’
In the first argument of ‘toPipe’, namely ‘(runToVectorP toVector)’
VectorPipe.hs:13:35-42: Could not deduce (y ~ X) …
from the context (PrimMonad m, G.Vector v a)
bound by the type signature for
vectorPipe :: (PrimMonad m, G.Vector v a) => Pipe a (v a) m ()
at /Users/casillas/GitHub/tau-sigma/VectorPipe.hs:12:15-62
‘y’ is a rigid type variable bound by
a type expected by the context: Proxy () a y' y m (v a)
at /Users/casillas/GitHub/tau-sigma/VectorPipe.hs:13:14
Expected type: Proxy () a y' y (ToVector v a m) r0
Actual type: Consumer a (ToVector v a m) r0
In the first argument of ‘runToVectorP’, namely ‘toVector’
In the first argument of ‘toPipe’, namely ‘(runToVectorP toVector)’
Compilation failed.
-}
有什么建议吗?可能是toVector
的签名不必要地缩小了吗? (我太喜欢管道菜鸟了... 编辑:我尝试将pipes-vector
中的签名更改为Consumer'
;代码编译,但看起来像vectorPipe
永远不会屈服。)
答案 0 :(得分:1)
好吧,我玩了好几天后想出了这个:
import Control.Monad
import Pipes
import Pipes.Core ((//>), (>\\), closed)
-- | Convert a 'Consumer' into a 'Pipe' that 'yield's the consumer's
-- final result.
fromConsumer :: Monad m => Consumer i m r -> Pipe i r m ()
fromConsumer c = c //> closed >>= yield
example1 :: MonadIO m => m ()
example1 = runEffect $ each "abcde" >-> fromConsumer (example' 3) >-> P.print
where
example' :: Monad m => Int -> Consumer a m [a]
example' n = replicateM n await
-- λ> example1
-- "abc"
-- | Convert a 'Producer' into a 'Pipe' that ignores its upstream
-- and sends the producer's contents downstream.
fromProducer :: Monad m => Producer o m r -> Pipe i o m r
fromProducer p = closed >\\ p
example2 :: MonadIO m => m ()
example2 = runEffect $ P.stdinLn >-> fromProducer (each "abcde") >-> P.print
-- Ignores stdin:
--
-- λ> example2
-- 'a'
-- 'b'
-- 'c'
-- 'd'
-- 'e'