답변:
reduce
그리고 apply
물론 단지 동등한있는 가변 인수에 대응 케이스에 모든 인수를 볼 필요가 연관 기능 (궁극적 인 결과의 측면에서 반환). 그것들이 결과적으로 동등 할 때, 나는 그것이 일반적으로 apply
완벽하게 관용적이지만, 많은 경우 reduce
에 동등 하지만 눈 깜박임의 일부를 깎을 수 있다고 말하고 싶습니다 . 다음은 이것을 믿는 나의 근거입니다.
+
reduce
변수 자체의 경우 두 가지 이상의 인수로 구현됩니다. 실제로, 이것은 가변적, 연관 기능 reduce
을 수행하기 위해 엄청나게 합리적인 "기본"방법처럼 보입니다. 아마도 internal-reduce
마스터에서 최근에 비활성화 된 1.2 참신을 통해 일을 가속화하기 위해 최적화를 수행 할 가능성이 있습니다. 바라건대 미래에 다시 도입되기를 희망합니다. vararg의 경우에 도움이 될 수있는 모든 기능을 복제하는 것은 어리석은 일입니다. 이러한 일반적인 경우 apply
에는 약간의 오버 헤드가 추가됩니다. (실제로 걱정할 필요는 없습니다.)
반면에 복잡한 함수는 일반적으로 구현할 수없는 최적화 기회를 활용할 수 있습니다 reduce
. 다음 apply
당신이 그 동안 활용할 수 있도록 것입니다 reduce
실제로 느려질 수 있습니다. 실제로 후자의 시나리오 발생하는의 좋은 예에 의해 제공된다 str
: 그것은 사용 StringBuilder
내부적의 사용으로 크게 도움이됩니다 apply
보다는 reduce
.
그래서, apply
의심 스러울 때 사용한다고 말하고 싶습니다 . 그리고 그것이 당신에게 아무것도 사지 않는다는 것을 알게되면 reduce
(그리고 이것은 곧 바뀔 것 같지 않다), reduce
당신이 그것을 느끼면 그 불필요한 불필요한 오버 헤드를 면도 하는 데 자유롭게 사용 하십시오.
sum
, Clojure에이 함수가 있다고합니다.이 함수를 호출 +
하여 사용할 수 있습니다 apply
. 당신이 무엇을 사용하는 - 가변 인자 기능이 제공되는 경우 :-) 진지하게 말하자면, 나는 일반적으로, 리스프 생각, 일반적으로 컬렉션에 래퍼 운영과 함께 아니에요 apply
(또는에 대해 reduce
당신이 더 의미가 알고있는 경우).
reduce
의심 스러울 apply
때, 최적화가 있는지 확실히 알고있을 때. reduce
의 계약이 더 정확하여 일반 최적화가 더 쉽습니다. apply
더 모호하므로 사례별로 만 최적화 할 수 있습니다. str
그리고 concat
두 널리 exceptons입니다.
reduce
및 apply
결과의 측면에서 동등하다, 내가 그들의 가변 오버로드를 최적화하는 방법을 가장 잘 알고 그냥 용어에서 그것을 구현하는 문제의 함수의 저자를 기대할 수있는 reduce
경우 그것이 실제로 가장 의미있는 것입니다 (그렇게하는 옵션은 항상 사용 가능하고 눈에 띄는 기본값을 만듭니다). 그래도 당신이 어디에서 왔는지 reduce
확실히 Clojure의 퍼포먼스 스토리의 중심에 있으며 매우 높아지고 명확하게 지정되어 있습니다.
이 답변을보고있는 초보자
에게는 조심하지 마십시오.
(apply hash-map [:a 5 :b 6])
;= {:a 5, :b 6}
(reduce hash-map [:a 5 :b 6])
;= {{{:a 5} :b} 6}
+와 같은 간단한 기능을 사용할 때는 실제로 어떤 기능을 사용하든 상관 없습니다.
일반적으로 아이디어는 reduce
누적 연산입니다. 누적 함수에 현재 누적 값과 하나의 새 값을 표시합니다. 함수의 결과는 다음 반복에 대한 누적 값입니다. 따라서 반복은 다음과 같습니다.
cum-val[i+1] = F( cum-val[i], input-val[i] ) ; please forgive the java-like syntax!
적용하려면 여러 스칼라 인수를 예상하는 함수를 호출하려고하지만 현재 콜렉션에 있으며 꺼내야합니다. 따라서 말하지 않고
vals = [ val1 val2 val3 ]
(some-fn (vals 0) (vals 1) (vals 2))
우리는 말할 수있다:
(apply some-fn vals)
그리고 다음과 같이 변환됩니다.
(some-fn val1 val2 val3)
따라서 "적용"을 사용하는 것은 시퀀스 주위의 "괄호 제거"와 같습니다.
주제에 조금 늦었지만이 예제를 읽은 후 간단한 실험을했습니다. 여기 내 repl의 결과이며 응답에서 아무것도 추론 할 수 없지만 reduce와 apply 사이에 일종의 캐싱 킥이있는 것 같습니다.
user=> (time (reduce + (range 1e3)))
"Elapsed time: 5.543 msecs"
499500
user=> (time (apply + (range 1e3)))
"Elapsed time: 5.263 msecs"
499500
user=> (time (apply + (range 1e4)))
"Elapsed time: 19.721 msecs"
49995000
user=> (time (reduce + (range 1e4)))
"Elapsed time: 1.409 msecs"
49995000
user=> (time (reduce + (range 1e5)))
"Elapsed time: 17.524 msecs"
4999950000
user=> (time (apply + (range 1e5)))
"Elapsed time: 11.548 msecs"
4999950000
clojure의 소스 코드를 살펴보면 내부 감소로 꽤 깨끗한 재귀가 줄어들고 적용 구현에 대해서는 아무것도 찾지 못했습니다. 내부 호출 감소 적용을위한 +의 Clojure 구현은 repl에 의해 캐시되며 4 번째 호출을 설명하는 것으로 보입니다. 누군가 여기서 실제로 일어나는 일을 분명히 할 수 있습니까?
range
전화를 time
양식 안에 넣지 마십시오 . 시퀀스 구성의 간섭을 제거하기 위해 외부에 두십시오. 제 경우에는 reduce
지속적으로 성능이 뛰어납니다 apply
.
적용의 아름다움은 함수가 주어지며 (이 경우 +) 엔딩 콜렉션이있는 중간에있는 인수에 의해 형성된 인수 목록에 적용될 수 있습니다. Reduce는 각각에 대해 함수를 적용하는 콜렉션 항목을 처리하기위한 추상화이며 가변 인수 경우와 작동하지 않습니다.
(apply + 1 2 3 [3 4])
=> 13
(reduce + 1 2 3 [3 4])
ArityException Wrong number of args (5) passed to: core/reduce clojure.lang.AFn.throwArity (AFn.java:429)
sum
haskell과 같은 내장 함수를 포함하지 않는 이유는 무엇입니까? 꽤 일반적인 작업 인 것 같습니다.