2014-02-08 69 views
3

我想了解管道解析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並在第一個元素上查看,然後將下3個元素作爲A類型,然後將以下三個元素作爲B,最後將其餘的值作爲A

回答

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 

這裏srcProducer B m rparser一個Parser B m (Maybe B, [A], [B])。我認爲其中的核心是剩餘部分就是在一些先前的解析操作之後在Parser-狀態邊界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)) 
+0

我更新了我的問題以澄清。我給出的例子表現了稍微不同的工作。將你提供的內容轉換爲原始功能似乎應該是微不足道的,但我一直無法做到。 –

+0

最後一個評論,我想我想通了:https://gist.github.com/snoyberg/8888998。我添加了一些跟蹤語句來試圖瞭解您對減少映射數量的意見。現在看起來整個流是來回轉換的,那是你在做什麼? –

+2

@MichaelSnoyman來回轉換似乎來自'zoom(piso ab)Pp.peek',除了那部分,只有中間的三個元素有'atob'叫它們,就像我所期望的那樣。 – Davorak