2017-03-10 4 views
1

connectpullFrom 기능이 purescript-coroutines에 있고 그 둘 모두를 사용해야하는 이유를 잘 모르겠습니다. 유형을 살펴보면, 그들이 의사 소통의 방향을 바꾸는 데 익숙해 진 것처럼 보입니다. (그것이 올바른 사고 방식인지는 확실하지 않습니다.) 나는 소비자와 생산자가 그렇다면purescript-coroutines에서`pullFrom`과`connect`의 차이점은 무엇입니까?

pullFrom :: forall o m a. MonadRec m => Consumer o m a -> Producer o m a -> Process m a 

connect :: forall o f m a. (MonadRec m, Parallel f m) => Producer o m a -> Consumer o m a -> Process m a 

...

consumer :: forall e a. (Show a) => Consumer a (Eff (console :: CONSOLE | e)) Unit 
consumer = forever do 
    s <- await 
    lift (log $ show s) 

numberProducer :: forall m. (Monad m) => Producer Int m Unit 
numberProducer = go 0 
    where 
    go i = do emit i 
      go (i + 1) 

그것은 소비자가 생산자로부터 당길 수 나에게 의미가, 나는 이것을 실행하면, 내가 볼 수 있습니다 숫자가 표시되고 있습니다 ...

main = do 
    runProcess (pullFrom consumer numberProducer) 

소비자에게 생산자가 있다면, 아무 것도하지 않는 것 같습니다. 나는 소비자에게 생산자를 연결할 때, 신호가 pullFrom과 반대 방향으로 가고 있다고 가정하고 있지만, 그 아이디어가 맞는지 확실하지 않습니다.

main = do 
    runProcess (connect producer consumer) 

답변

2

글쎄, 이것은 재미가 조금 놀랍습니다.

pullFrom가 도입되어 소비자가 프로세스가 형성 될 때 "책임이 있음"- 소비자가 열려있는 동안 (입력을 기다리는) 프로세스가 존재합니다.

connect은 생산자 또는 고객이 열려있는 한 실행되며 두 프로세스가 모두 완료되면 프로세스가 종료됩니다. 과정 만 consumer에 의존하기 때문에이 필요하지 않습니다 pullFrom - 생성 된 프로세스가 소비자와 생산자 모두에 따라 달라집니다로 이것을 달성하기

connectParallel 클래스 제약 조건이있다.

"재미"가 놀라는 순간입니다. 잠시 혼란스러워합니다. EffParallel이 아니므로 코드가 어떻게 작동합니까? 이 main이 유형을 추론하는 것 때문입니다 : 프로그램이 실행될 때 JS에서, main이 사전은 Parallel 제한 조건에 대해 전달 될 것으로 예상되기 때문에

main :: forall t. (Parallel t (Eff (console :: CONSOLE))) => Eff (console :: CONSOLE) Unit 

그래서 아무것도, 발생하지, 다음 Eff을 평가한다. main에 대한 생성 된 호출은 Main.main();이므로 Main.main(impossibleParallelDictionary)(); 일 필요가 있으므로 실제로는 Eff을 평가하지 않습니다. 당신의 main이 유형을 추가

시도 :

main :: Eff (console :: CONSOLE) Unit 

그리고 당신이 더 이상 확인 입력하지 않는 것을 볼 수 있습니다.

당신은 생각이에 대한 Aff을 사용할 수 있습니다

AffconnectpullFrom의 차이는이 예를 들어, 구별 : 우리는 약간의 예제를 수정하는 경우, 우리는 그 차이의 그림을 볼 수 있습니다

import Prelude 

import Control.Coroutine (Consumer, Producer, await, connect, emit, runProcess) 
import Control.Monad.Aff (Aff, launchAff) 
import Control.Monad.Aff.Console (CONSOLE, log) 
import Control.Monad.Eff (Eff) 
import Control.Monad.Eff.Exception (EXCEPTION) 
import Control.Monad.Rec.Class (forever) 
import Control.Monad.Trans.Class (lift) 

consumer :: forall e a. (Show a) => Consumer a (Aff (console :: CONSOLE | e)) Unit 
consumer = forever do 
    s <- await 
    lift (log $ show s) 

numberProducer :: forall m. (Monad m) => Producer Int m Unit 
numberProducer = go 0 
    where 
    go i = do emit i 
      go (i + 1) 

main :: Eff (err :: EXCEPTION, console :: CONSOLE) Unit 
main = void $ launchAff $ runProcess (connect numberProducer consumer) 

:

import Prelude 

import Control.Coroutine (Consumer, Producer, await, emit, connect, runProcess) 
import Control.Monad.Aff (Aff, launchAff, later') 
import Control.Monad.Aff.Console (CONSOLE, log) 
import Control.Monad.Eff (Eff) 
import Control.Monad.Eff.Exception (EXCEPTION) 
import Control.Monad.Trans.Class (lift) 

consumer :: forall e a. (Show a) => Consumer a (Aff (console :: CONSOLE | e)) Unit 
consumer = do 
    s <- await 
    lift (log $ show s) 

numberProducer :: forall eff. Producer Int (Aff eff) Unit 
numberProducer = do 
    emit 0 
    lift $ later' 10000 $ pure unit 

main :: Eff (err :: EXCEPTION, console :: CONSOLE) Unit 
main = void $ launchAff $ runProcess (connect numberProducer consumer) 

이렇게하면 프로그램이 0을 인쇄하고 10 초 기다렸다가 종료합니다. consumer `pullFrom` numberProducer에 대해 connect numberProducer consumer을 전환하면 프로그램이 0을 인쇄하고 즉시 종료됩니다.

+0

감사합니다. gb, 의미가 있습니다! "생산자 또는 소비자가 열려있는 한 연결 실행에 대한 참고 사항을 분명히 할 수 있으며 프로세스가 완료 될 때만 프로세스가 종료됩니다." 그 말은 "어느 것이 든 완료되면 끝나야합니까?" 하나의 값만 기다리는 소비자를 만듭니다 (즉, 위의 소비자 함수에서 '영원히'를 제거합니다), numberProducer는 여전히 '열리 며'프로세스를 열어 두는 것처럼 보입니다. – Albtzrly

+0

'pullFrom'과'connect'의 차이점을 관찰 할 수있는 답을 보여주는 또 다른 예제를 편집했습니다. 나는 "open"에 대한 나의 설명이 그것을 표현하는 최선의 방법이 아닐 수도 있다고 생각한다 - 내 설명에서 "emit step"을위한 기능이 아직 완성되지 않았다면 생산자는 "open"이다. 따라서 무한한 생산자와 한정된 소비자가 있더라도 소비자는 '연결'을 통해 (또는 그 반대로) 프로세스가 종료됩니다. –

+0

추가 예를 보내 주셔서 감사합니다. – Albtzrly