Clojure에서 lazy 시퀀스를 non-lazy로 변환하는 방법


95

Clojure에서 다음을 시도했는데 지연되지 않은 시퀀스의 클래스가 반환 될 것으로 예상했습니다.

(.getClass (doall (take 3 (repeatedly rand))))

그러나 이것은 여전히 clojure.lang.LazySeq. 내 생각 엔 doall전체 시퀀스를 평가하지만 메모 화에 여전히 유용하므로 원래 시퀀스를 반환합니다.

그렇다면 게으른 시퀀스에서 지연되지 않은 시퀀스를 만드는 관용적 수단은 무엇입니까?


나는 아무도 당신이 왜 당신이 반환 값의 실제 유형에 대해 걱정하는지 묻지 않았다는 것에 놀랐습니다doall
tar

벡터로 변환 할 수 있습니다.(vec (take 3 (repeatedly rand)))
Kris

답변:


161

doall당신이 필요한 전부입니다. (가) 그냥 있기 때문에 seq이 유형 LazySeq은 평가를 보류중인 것을 의미하지 않는다. Lazy seq는 결과를 캐시하므로 모든 작업 을 강제 seqdoall수행하기 위해 한 번 (그대로 ) 게으른 상태로 걸어 가기 만하면됩니다. 전체 컬렉션을 강제로 평가 seq하지 않습니다 .


2
나는 이것을 받아 들인 대답으로 변경했습니다. 관련 메모에서 LazySeq가 이전에 평가되었는지 어떻게 확인할 수 있습니까?
Tim Clemons

10
나는 당신이 그냥 전화를 믿습니다 realized?.
toofarsideways

1
realize일치 하는 작업 이있을 것입니다 realized?.
Reut Sharabani

이것은 모두 매우 좋습니다. 그러나 contains?lazy seq를 실현했는지 여부 와 같은 일부 기능은 질문에 대한 특정 질문에 대한 답변이지만 질문의 제목에는 덜합니다.
matanster

75

이것은 어느 정도 분류의 문제입니다. 게으른 시퀀스는 목록, 벡터 또는 맵과 같은 시퀀스 유형 중 하나 입니다. 그래서 대답은 당연히 "당신이 얻고 자하는 non lazy sequence의 유형에 달려
있습니다.

  • 전 게으른 (완전히 평가 된) 게으른 시퀀스 (doall ... )
  • 순차 액세스 목록 (apply list (my-lazy-seq)) OR (into () ...)
  • 나중에 랜덤 액세스를위한 벡터 (vec (my-lazy-seq))
  • 특별한 목적이 있다면지도 나 세트.

당신은 당신이 필요로하는 대부분의 스위트에 어떤 유형의 시퀀스를 가질 수 있습니다.


이것이 최고의 답변입니다.
Felipe

4
받아 들여진 대답은 기술적으로 정확하지만이 대답은 나에게 가장 유용했습니다. 벡터에 대한 함수를 매핑 한 다음 결과를 파일에 뱉어 내려고했는데, doall을 호출 한 후에도 파일에는 시퀀스의 내용 대신 "clojure.lang.LazySeq@address"가 포함되어 있습니다. 반환 된 값 맵에서 vec를 호출하면 파일에 뱉어내는 데 필요한 정보를 얻었습니다.
Jesse Rosalia

1
@JesseRosalia SO 모두에서 유일한 Rich Hickey 응답이 기술적으로 정확하다는 것을 아는 것이 좋습니다. ;-)
Phil Cooper

(vec (my-lazy-seq))다음과 같은 상황에서는별로 좋지 않습니다 . lazy-seq를 생성 (vec (json/parse-string "{\"foo\":\"bar\"}")) ;; => [["foo" "bar"]]하기로 cheshire선택 했기 때문에(json/parse-string)
codeasone

위의 완화 방법은 eager를 사용하는 것이 었습니다(json/parse-string-strict)
codeasone

22

이 부자는 그의 클로저를 알고있는 것 같고 절대적으로 옳습니다.
그러나 귀하의 예제를 사용하는이 코드 스 니펫 이이 질문에 대한 유용한 보완이 될 수 있다고 생각합니다.

=> (realized? (take 3 (repeatedly rand))) 
false
=> (realized? (doall (take 3 (repeatedly rand)))) 
true

실제로 유형 은 변경되지 않았지만 실현


2
하지만 전체 시퀀스를 강제 realized?로 반환 할 필요가 없다는 점에 주목할 가치가 true있습니다. 예(let [r (range) r? (realized? r)] (doall (take 1 r)) [r? (realized? r)]) => [false true]
알렉스 코번 트리

22
이 풍부한 사람 : D 하하
니므롯

10
@nimrod :) 그러나 말장난은 "hís clojure"에 있어야했습니다.
Peter

10
모르는 사람들을 위해 "The Rich guy"는 Clojure를 발명했습니다.
erturne 2014

1
귀하의 예를 반환 @AlexCoventry[true true]

7

블로그 게시물 doall에서 재귀 적이 지 않다는 것을 우연히 발견했습니다 . 이를 위해 게시물의 첫 번째 댓글이 트릭을 수행했음을 발견했습니다. 라인을 따라 뭔가 :

(use 'closure.walk)
(postwalk identity nested-lazy-thing)

map오류 조건을 강제하기 위해 일부 중첩 된 응용 프로그램의 평가를 강제하려는 단위 테스트에서이 기능이 유용하다는 것을 알았습니다 .


5
(.getClass (into '() (take 3 (repeatedly rand))))

3
이것은 끔찍한 생각입니다. 입력 시퀀스를 반대로합니다.
amalloy

3
물론,이 경우 입력을 뒤집어도 아무 차이가 없습니다. 3 개의 난수이기 때문입니다 .... :-)
mikera
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.