我试图理解pipe-parse 3.0如何适用于span
和splitAt
以外的案例,并且无法弄清楚如何让事情发挥作用。基本思想是我有一个同构,我想映射所有输入值以从类型A
转换为类型B
。然后,我希望将所有剩菜从B
转换回A
。我将如何在pipes-parse
中完成此任务?
为了进行比较,代码在conduit
中的内容如下:
import Control.Applicative ((<$>), (<*>))
import Data.Conduit (yield, ($$), (=$=))
import Data.Conduit.Extra (fuseLeftovers)
import qualified Data.Conduit.List as CL
newtype A = A Int
deriving Show
newtype B = B Int
deriving Show
atob (A i) = (B i)
btoa (B i) = (A i)
main :: IO ()
main = do
let src = mapM_ (yield . A) [1..10]
res <- src $$ (,,,)
<$> fuseLeftovers (map btoa) (CL.map atob) CL.peek
<*> CL.take 3
<*> (CL.map atob =$= CL.take 3)
<*> CL.consume
print res
编辑:澄清一下,这是我上面代码的输出:
(Just (B 1),[A 1,A 2,A 3],[B 4,B 5,B 6],[A 7,A 8,A 9,A 10])
请注意,原始流的类型为A
。我们转换为B
并查看第一个元素,然后将接下来的3个元素作为A
类型,然后将以下三个元素作为B
,最后取剩余的为A
。
答案 0 :(得分:3)
我是通过引入辅助镜头组合器piso :: Iso' a b -> Iso' (Producer a m r) (Producer b m r)
import Control.Applicative
import Control.Lens (view, from, zoom, iso, Iso')
import Control.Monad.State.Strict (evalState)
import Pipes
import Pipes.Core as Pc
import qualified Pipes.Parse as Pp
import qualified Pipes.Prelude as P
newtype A = A Int
deriving Show
newtype B = B Int
deriving Show
atob (A i) = B i
btoa (B i) = A i
ab :: Iso' A B
ab = iso atob btoa
piso :: Monad m => Iso' a b -> Iso' (Producer a m r) (Producer b m r)
piso i = iso (P.map (view i) <-<) (>-> P.map (view $ from i))
main :: IO ()
main = do
let src = P.map atob <-< P.map A <-< each [1..10]
let parser = (,,) <$> zoom (Pp.splitAt 1) Pp.peek
<*> zoom (Pp.splitAt 3 . piso (from ab)) Pp.drawAll
<*> Pp.drawAll
let res = evalState parser src
print res
此处src
是Producer B m r
和parser
a Parser B m (Maybe B, [A], [B])
。我认为这样做的核心是,剩余事件正是在Parser
- 状态绑定Producer
之后发生的事情。因此,您可以像平常一样使用zoom
来修改Producer
但是您喜欢。
请注意,我们可以翻转镜头的顺序并执行zoom (piso (from ab) . Pp.splitAt 3) Pp.drawAll
但是因为镜头从左向右下降意味着我们在关注下三个元素之前修改整个Producer
。使用我的主示例中的顺序可以减少A
和B
之间的映射数量。
view (Pp.splitAt 3 . piso (from ab))
:: Monad m => Producer B m x -> (Producer A m (Producer B m x))
-- note that only the outer, first Producer has been mapped over, the protected,
-- inner producer in the return type is isolated from `piso`'s effect
view (piso (from ab) . Pp.splitAt 3)
:: Monad m => Producer B m x -> (Producer A m (Producer A m x))