Clojure : 휴식 대 다음
나는 사이의 차이를 이해하는 힘든 시간을 보내고있어 rest
및 next
Clojure의의를. 게으름에 대한 공식 사이트의 페이지 는 선호도가 아마도를 사용하는 것이되어야 함을 rest
나타내지 만 둘의 차이점을 명확하게 설명하지는 않습니다. 아무도 통찰력을 제공 할 수 있습니까?
링크 한 페이지 next
가 설명했듯이, rest
반환할지 nil
또는 seq 인지 알기 위해 게으른 사기의 구조를 평가해야하기 때문에 (새로운 동작)보다 엄격 합니다 .
rest
반면에 항상 seq를 반환하므로 실제로 결과를 사용할 때까지 평가할 필요가 없습니다 rest
. 즉, rest
은 next
.
이것 만 있으면 쉽습니다 :
(next '(1))
=> nil
따라서 next
다음을 살펴보고 라인이 비어 있으면 nil
빈 seq 대신 반환 됩니다. 즉, (반환 할 첫 번째 항목까지) 미리보기가 필요하므로 완전히 게으르지 않습니다 (다음 값은 필요하지 않지만 next
미리보기 위해 컴퓨팅 시간을 낭비 함).
(rest '(1))
=> ()
rest
앞을 보지 않고 나머지 seq 만 반환합니다.
아마도 당신은 왜 여기에서 두 가지 다른 것을 사용하는 것을 귀찮게 생각합니까? 그 이유는 일반적으로 seq에 아무것도 남아 있지 않은지 확인하고 그냥 반환하기를 원하기 때문입니다 nil
. 그러나 어떤 경우에는 성능이 매우 중요하고 하나 이상의 항목을 평가하는 것은 사용할 수있는 엄청난 노력을 의미 할 수 있습니다 rest
.
next
입니다 (seq (rest ...))
.
rest
시퀀스의 나머지 부분을 반환합니다. 시퀀스의 해당 부분이 아직 실현 rest
되지 않은 경우 강제로 실행하지 마십시오. 시퀀스에 더 많은 요소가 남아 있는지 여부도 알려주지 않습니다.
next
동일한 작업을 수행하지만 시퀀스의 적어도 하나의 요소가 실현되도록 강제합니다. 따라서 next
returns nil
이면 시퀀스에 더 이상 요소가 남아 있지 않음을 알 수 있습니다.
next
이스케이프 평가가 더 간단하고 깔끔 하기 때문에 이제는 reursion과 함께 사용하는 것을 선호합니다 .
(loop [lst a-list]
(when lst
(recur (next lst))
vs
(loop [lst a-list]
(when-not (empty? lst) ;; or (when (seq? lst)
(recur (rest lst))
그러나을 rest
사용하는 경우는 컬렉션을 대기열 또는 스택으로 사용하는 경우입니다. 이 경우 마지막 항목을 팝하거나 대기열에서 제거 할 때 함수가 빈 컬렉션을 반환하도록합니다.
다음은 "mundane"재귀 (스택 사용)를 사용하거나 recur
(꼬리 재귀 최적화를 사용하여 실제로 루프를 사용하여 ) 시퀀스를 순회하는 코드를 작성할 때 유용한 작은 테이블 입니다.
rest
및의 동작 차이에 유의하십시오 next
. seq
이것 과 결합 하면 다음 관용구로 이어집니다. 여기서 end-of-list는 테스트를 거쳐 seq
나머지 목록은 rest
( "The Joy of Clojure"에서 발췌)를 통해 얻습니다 .
; "when (seq s)":
; case s nonempty -> truthy -> go
; case s empty -> nil -> falsy -> skip
; case s nil -> nil -> falsy -> skip
(defn print-seq [s]
(when (seq s)
(assert (and (not (nil? s)) (empty? s)))
(prn (first s)) ; would give nil on empty seq
(recur (rest s)))) ; would give an empty sequence on empty seq
왜 next
더 열심 rest
입니까?
경우 (next coll)
평가 결과가 될 수 있습니다 nil
. nil
호출자가의 진실성을 기반으로 분기 할 수 있으므로 이는 즉시 알려야합니다 (즉, 실제로 반환되어야 함 ) nil
.
If (rest coll)
is evaluated, the result cannot be nil
. Unless the caller then tests the result for empty-ness using a function call, generation of a "next element" in a lazy-seq can be delayed to the time it is actually needed.
Example
A completely lazy collection, all the computations are "on hold until needed"
(def x
(lazy-seq
(println "first lazy-seq evaluated")
(cons 1
(lazy-seq
(println "second lazy-seq evaluated")
(cons 2
(lazy-seq
(println "third lazy-seq evaluated")))))))
;=> #'user/x
The computation of "x" is now suspended at the first "lazy-seq".
Using the eager next after that, we see two evaluations:
(def y (next x))
;=> first lazy-seq evaluated
;=> second lazy-seq evaluated
;=> #'user/y
(type y)
;=> clojure.lang.Cons
(first y)
;=> 2
- The first lazy-seq is evaluated, leading to the printout
first lazy-seq evaluated
- This results in a nonempty structure: a cons with 1 on the left and a lazy-seq on the right.
next
may have to returnnil
if the right branch is empty. So we need to check one level deeper.- The second lazy-seq is evaluated, leading to the printout
second lazy-seq evaluated
- This results in a nonempty structure: a cons with 2 on the left and a lazy-seq on the right.
- So don't return
nil
, return the cons instead. - When obtaining the
first
ofy
, there is nothing do do except retrieve 2 from the already-obtained cons.
Using the lazier rest
, we see one evaluation (note that you have to redefine x
first to make the this work)
(def y (rest x))
;=> first lazy-seq evaluated
;=> #'user/y
(type y)
;=> clojure.lang.LazySeq
(first y)
;=> second lazy-seq evaluated
;=> 2
- The first lazy-seq is evaluated, leading to the printout
first lazy-seq evaluated
- This results in a nonempty structure: a cons with 1 on the left and a lazy-seq on the right.
rest
never returnsnil
, even if the lazy-seq on the right would evaluate to the empty seq.- If the caller needs to know more (is the seq empty?), he can perform the appropriate test later on the lazy-seq.
- So we are done, just return the lazy-seq as result.
- When obtaining the
first
ofy
, the lazy-seq needs to be evaluated one step further to obtain the 2
Sidebar
Note that y
's type is LazySeq
. This may seem obvious, but LazySeq
is not at "thing of the language", it is a "thing of the runtime", representing not a result but a state of computation. In fact (type y)
being clojure.lang.LazySeq
just means "we don't know the type yet, you have to do more to find out". Whenever a Clojure function like nil?
hits something that has type clojure.lang.LazySeq
, computation will occur!
P.S.
In Joy of Clojure, 2nd edition, on page 126, there is an example using iterate
to illustrate the difference between next
and rest
.
(doc iterate)
;=> Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free
; of side-effects
결과적으로이 예제는 작동하지 않습니다. 이 경우 실제로 next
와 사이의 동작에는 차이가 없습니다 rest
. 이유가 확실 next
하지 않은 경우 nil
여기에 반환되지 않고 rest
.
(defn print-then-inc [x] (do (print "[" x "]") (inc x)))
(def very-lazy (iterate print-then-inc 1))
(def very-lazy (rest(rest(rest(iterate print-then-inc 1)))))
;=> [ 1 ][ 2 ]#'user/very-lazy
(first very-lazy)
;=> [ 3 ]4
(def less-lazy (next(next(next(iterate print-then-inc 1)))))
;=> [ 1 ][ 2 ]#'user/less-lazy
(first less-lazy)
;=> [ 3 ]4
참고 URL : https://stackoverflow.com/questions/4288476/clojure-rest-vs-next
'UFO ET IT' 카테고리의 다른 글
텍스트 영역의 오른쪽 하단 모서리에있는 점을 제거하는 방법은 무엇입니까? (0) | 2020.11.17 |
---|---|
pip 패키지에 대한 종속성 트리를 표시하는 방법이 있습니까? (0) | 2020.11.17 |
토큰 만료-JSON REST API-오류 코드 (0) | 2020.11.17 |
How do I test (in one line) if command output contains a certain string? (0) | 2020.11.17 |
Django에서 커스텀 미들웨어를 설정하는 방법 (0) | 2020.11.17 |