我试图了解管道解析3.0在spansplitAt之外的情况下如何工作,并且无法完全弄清楚如何使事情正常进行。基本思想是我具有同构性,我想映射所有输入值以从类型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并查看第一个元素,然后将接下来的三个元素作为类型A,然后将后面的三个元素作为B,最后将其余的元素作为A

最佳答案

我通过引入辅助镜头组合器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


此处srcProducer B m rparserParser B m (Maybe B, [A], [B])。我认为,这样做的核心是,残留物就是经过某些先前的解析操作后在Parser -State绑定的Producer中发生的事情。因此,您可以像平常一样使用zoom随意修改该Producer

请注意,我们可以翻转镜头的顺序并执行zoom (piso (from ab) . Pp.splitAt 3) Pp.drawAll,但是由于镜头从左到右下降,这意味着我们在着眼于接下来的三个元素之前要修改整个Producer。在我的主要示例中使用该顺序可以减少AB之间的映射数。

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))

关于haskell - 使用管道分析来保留带有 map 的剩菜,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21649920/

10-10 18:19