2014-02-08 8 views
3

spansplitAt 외의 경우에 pipe-parse 3.0이 어떻게 작동하는지 이해하려고 노력 중이며 작동 방법을 파악할 수 없습니다. 기본 개념은 동형 이성을 가지고 있으며 모든 입력 값을 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으로 가져옵니다.

답변

3

여기 src

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 

piso :: Iso' a b -> Iso' (Producer a m r) (Producer b m r)Producer B m r과는 parserParser 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