2014-09-25 4 views
8

저는 core.async 라이브러리를 새로 작성했습니다. 실험을 통해이 라이브러리를 이해하려고합니다.core.async 블록에서 for 루프를 사용할 수 없습니까?

내가 시도 때 :

(let [i (async/chan)] (async/go (doall (for [r [1 2 3]] (async/>! i r))))) 

를 그것은 나에게 매우 이상한 예외 제공 :

CompilerException java.lang.IllegalArgumentException: No method in multimethod '-item-to-ssa' for dispatch value: :fn 

을 내가 다른 코드 시도 :

(let [i (async/chan)] (async/go (doseq [r [1 2 3]] (async/>! i r)))) 

이 더 컴파일러 예외에서이 없습니다를 모든.

나는 완전히 혼란 스럽다. 무슨 일인데?

+1

"for"in clojure is not a loop - 목록 이해입니다. 이 점을 염두에두고''for'' 예제는'>에 영향을주는 부작용을 나타내는 관용적 인 방법이 아닙니다!'함수. 어쩌면 컴파일러 메시지가 개선되어야 할 수도 있지만 근본적인 문제는 이런 식으로''for ''를 사용하는 것이 감각을 갖지 못한다는 것입니다. ''doseq''는 완벽합니다. – sw1nn

+0

>! 블록을 읽으면 다른 사람이 채널에서 읽을 때까지 기다립니다. 먼저 파트 읽기를 시도하거나 put을 사용하십시오! – edbond

+0

@edbond 와우,이게 실제로 작동합니다 ..하지만 더 혼란 스럽습니다. Timothy Baldridge가 async/go가'async/go' 블록에서'fn'을 처리 할 수 ​​없다고 말하지 않았습니까? – xudifsd

답변

16

그래서 Clojure go-block은 많은 이유로 함수 경계에서 변환을 중지하지만 가장 큰 것은 단순성입니다.

(go (lazy-seq (<! c))) 

이런 식으로 컴파일 된 가져옵니다 :

이제
(go (clojure.lang.LazySeq. (fn [] (<! c)))) 

이의이 진짜 빨리 ... 무엇을해야이 복귀에 대해 생각하게 게으른 서열을 구성 할 때 가장 일반적으로 볼 수있다? 당신이 원했던 것이 c에서 가져온 값을 포함하고있는 lazy seq이지만, <!은 함수의 나머지 코드를 콜백으로 변환 할 필요가 있지만, LazySeq은 함수가 동기 될 것으로 기대하고있다. 이 한계를 극복하는 방법은 없습니다.

그래서 macroexpand for이 실제로 루프되지 않는다는 것을 알게 될 것입니다. 대신에 결국 lazy-seq을 호출하는 코드 묶음으로 확장되므로 주차 ops가 본문 내부에서 작동하지 않습니다. doseq (및 dotimes)은 loop/recur에 의해 뒷받침되므로 완벽하게 정상적으로 작동합니다.

with-bindings이 하나의 예가 될 수있는 몇 가지 다른 장소가 있습니다. 기본적으로 매크로가 core.async 파킹 작업을 중첩 된 함수에 집어 넣으면이 오류가 발생합니다.

내 제안은 가능한 한 간단하게 이동 블록의 몸을 유지하는 것입니다. 순수 함수를 작성한 다음 이동 블록 본문을 IO를 수행 할 위치로 처리하십시오.

------------ 기능의 경계에서 정지 번역에 의해 편집 -------------

,이 의미 : 이동 블록은 소요 몸체를 상태 머신으로 변환합니다. <!>! 또는 alts! (및 기타 몇 개)에 대한 각 호출은 블록 실행이 일시 중지 될 수있는 상태 시스템 전환으로 간주됩니다. 각 포인트에서 기계는 콜백으로 바뀌고 채널에 연결됩니다. 이 매크로가 fn 양식에 도달하면 번역이 중지됩니다. 따라서 코드 블록 내부의 함수가 아닌 이동 블록 안에서만 <!에 전화를 걸 수 있습니다.

이것은 core.async의 마법의 일부입니다. go 매크로가 없다면, core.async 코드는 다른 langauges에서 callback-hell처럼 보일 것입니다.

+1

'함수 경계에서 번역 중지'란 무엇을 의미하는지 설명해 주시겠습니까? – Chiron

+1

원래의 게시물 –

+0

에 추가되었습니다. core.async가 fn에 하나 이상의 메소드를 추가하고 더 나은 예외를 throw 할 수 있습니다. 비우호적 인 초심자입니다. – xudifsd

관련 문제