정확히 Proxy
유형의 pipes
입니다. 도식적으로 다음과 같이 보입니다.
Upstream | Downstream
+---------+
| |
a' <== <== b'
| |
a ==> ==> b
| | |
+----|----+
v
r
이 인터페이스에는 업스트림 인터페이스와 다운 스트림 인터페이스라는 두 개의 인터페이스가 있습니다. 두 인터페이스에 대한 정보를 보내고받습니다. 이는 스택의 계층과 유사합니다. "업스트림"이 스택 프레임 위에있을 수 있습니다. "다운 스트림"은 그 아래의 스택 프레임 일 수 있습니다. 즉
request :: Monad m => a' -> Proxy a' a b' b m a
, request
유형 a
의 응답 유형 a'
업스트림 및 대기의 값을 보냅니다
상류 인터페이스와 통신하려면이 유형이있는
request
를 사용합니다.
request
의 이중
다운 스트림 인터페이스에 통신하는,
respond
이다
respond :: Monad m => b -> Proxy a' a b' b m b'
respond
형 b'
의 응답 타입 b
하류 대기의 값을 보낸다.
Proxy
은 세 가지 상태 중 하나 일 수 있습니다.그것은있을 수 있습니다 :
그것의 종류의 응답을 기다리는 것 그것이 a
기다리고 있음을 나타냅니다 :
waitingUp :: a -> Proxy a' a b' b m r
유형 w 울드 그것이 b'
기다리고 있음을 나타냅니다
waitingDn :: b' -> Proxy a' a b' b m r
그것의 유형은 모든 값이 기다리고 아니에요 것을 나타냅니다 :
notWaiting :: Proxy a' a b' b m r
다음 세 가지 상태를 연결할 수있는 방법은 네 가지가 있습니다.
- 다운 스트림에서 대기중인
Proxy
을 활성 Proxy
에 연결하면 새로운 활성 Proxy
이 생성됩니다.
이것은 (+>>)
운영자가하는 일입니다 :
(+>>)
:: Monad m
=> (b' -> Proxy a' a b' b m r) -- Waiting on downstream
-> Proxy b' b c' c m r -- Active
-> Proxy a' a c' c m r -- Active
- 새로운 활성
Proxy
생성 상류에 대기 Proxy
에 활성 Proxy
를 연결합니다.
이것은 (>>~)
운영자가하는 일입니다 : 상류에서 대기중인
(>>~)
:: Monad m
=> Proxy a' a b' b m r -- Active
-> (b -> Proxy b' b c' c m r) -- Waiting on upstream
-> Proxy a' a c' c m r -- Active
- 연결이 개
Proxy
들, 상류에서 대기 새로운 Proxy
을 생성 할 수 있습니다.
이것은 (>~>)
운영자가하는 일입니다 : 모두 다운 스트림에서 대기중인
(>~>)
:: Monad m
=> (a -> Proxy a' a b' b m r) -- Waiting on upstream
-> (b -> Proxy b' b c' c m r) -- Waiting on upstream
-> (a -> Proxy a' a c' c m r) -- Waiting on upstream
- 연결이 개
Proxy
들, 다운 스트림을 기다리는 새로운 Proxy
을 생성 할 수 있습니다.
이것은 (>+>)
운전자가 무엇입니다
(>+>)
:: Monad m
=> (b' -> Proxy a' a b' b m r) -- Waiting on downstream
-> (c' -> Proxy b' b c' c m r) -- Waiting on downstream
-> (c' -> Proxy a' a c' c m r) -- Waiting on downstream
여기 구현이 방법 연결된 세 개의 스택 프레임의 예이다.나는 구현이 완전히 대칭이지만, 스택 상류에서 시작하는 규칙을 사용하고 당신이 원하는 경우 반대 규칙을 사용할 수 있습니다
import Pipes.Core
import Pipes
-- +-+-- Closed upstream interface
-- | |
-- v v
up ::() -> Proxy X() String Int IO()
up() = do
str1 <- respond 4
lift (putStrLn str1)
str2 <- respond 5
lift (putStrLn str2)
middle :: Int -> Proxy String Int Double Char IO()
middle int = do
lift (print int)
double <- respond (head (show int))
lift (print double)
int' <- request (show double)
middle int'
-- Closed downstream interface --+-+
-- | |
-- v v
down :: Char -> Proxy Double Char() X IO()
down char1 = do
lift (print char1)
char2 <- request (1.0)
lift (print char2)
char3 <- request (2.0)
lift (print char3)
-- +-+--+--+-- Everything closed
-- | | | |
-- v v v v
total ::() -> Proxy X()() X IO()
total = up >~> middle >~> down
main :: IO()
main = runEffect $ total()
이 다음과 같은 출력이 생성
>>> main
4
'4'
1.0
1.0
5
'5'
2.0
2.0
시도를 up
Proxy
부터 시작하여 손으로 실행 경로를 추적합니다. 값이 up
respond
인 값이 0이 될 때마다 제어는 middle
으로, 매번 middle
은이되고 제어 값은 down
이됩니다. 반대로 down
request
값이 0이 될 때마다 제어는 middle
으로, 매번 middle
request
은 up
으로 제어되지 않습니다. 체인의 파이프가 종료되면 전체 체인이 종료됩니다.
편집 : 질문에 대답하려면 네 결과에 따라 동작을 변경할 수 있습니다. foo
및 bar
가 동일한 입력과 출력을 모두 Proxy
들입니다
middle :: Int -> Proxy String Int Double Char IO()
middle int = do
lift (print int)
double <- respond (head (show int))
case double of
0.0 -> foo
_ -> bar
... middle
등 :
foo :: Proxy String Int Double Char IO()
bar :: Proxy String Int Double Char IO()
두 Proxy
의 염기 서열을 때, 두 번째 Proxy
그냥 이런 middle
쓰기 첫 번째 Proxy
이 끝나는 곳에서 시작됩니다. request
및 respond
과 같은 기본 명령 시퀀싱에 국한되지 않습니다. 동일한 업스트림 및 다운 스트림 인터페이스를 공유하는 한 Proxy
범위 내에서 서브 루틴으로 임의의 단계 수를 가진 Proxy
을 호출 할 수 있습니다.
'애니메이션'유형은'pipes' 또는'conduit' 라이브러리가 제공하는 것과 비슷합니다. – cdk
@cdk, 잘 알지는 못하지만, 둘 다 데이터 변환에 방해를받는 것 같습니다. 중요한 것은 각 애니메이션이 스스로를 대체 할 수 있어야한다는 것입니다. –