2011-08-13 1 views
6

나는 시퀀스를 훈련을 4clojure.com으로 계산하려고합니다. 이 연습에서는 count 기능을 사용하지 않고 컬렉션의 요소 수를 계산합니다.Clojure에서 조건부 if에서 recur를 호출하려면 어떻게해야합니까?

나는 재귀를 통해 rest의 사용으로이 작업을 수행 할 수 있다고 생각했습니다. 내가 얻은 것이 비어 있지 않으면 1 + recur on the sequence rest returned을 반환합니다. 문제는 내가 맨 마지막 문장으로 recur를 호출하고있어 비록

java.security.PrivilegedActionException: java.lang.UnsupportedOperationException: 
Can only recur from tail position 

를 그만 둘 것이있다.

(fn [coll] (let [tail (rest coll)] 
      (if (empty tail) 
       1 
       (+ 1 (recur tail))))) 

내가 누락 된 상품이 있습니까?

답변

8

recur에 대한 호출이 아닌 마지막 진술이 추가되었으므로 작동하지 않습니다. 그것이 if 안에 있다는 사실은 그것과 아무 관련이 없습니다. (fn [coll] (let [tail (rest coll)] (+ 1 (recur tail))))도 작동하지 않습니다. (recur tail (+ acc 1)) 대신 :

꼬리 재귀 하나에이 같은 기능을 설정하는 일반적인 방법은 기능을 사용하면 최대 추가하고 다음과 같이 재귀있는 값에 대한 누적을 보유하고 두 번째 인수를 취할 수 있도록하는 것입니다 recur의 결과에 1을 더하려고합니다.

일반적으로 : recur의 결과 (예 : 1을 추가하는 것과 같은)를 수행하는 경우 꼬리 위치에있을 수 없으므로 작동하지 않습니다.

6

당신이 얻는 오류는 최종 표현이 (+ 1 (recur tail))이라는 것이 꼬리 - 통화 최적화가 최적화 될 수 없다는 것을 지적하고 있습니다. 문제는 함수의 결과를 평가하기 위해 스택에 (+ 1 ...) 수식을 유지해야한다는 것입니다. 테일 호출 최적화는 호출 된 함수의 값이 인 경우에만 발생하며 호출을 수행하는 함수의 반환을 알기 위해 필요한 것은입니다.

쓰려고하는 것은 거의 fold입니다. 이 경우 함수는 컬렉션의 나머지 부분과 현재까지의 개수를 따라 가야합니다.

(fn [count coll] (let [tail (rest coll)] 
    (if (empty tail) 
     count 
     (recur (+ 1 count) tail))))) 
관련 문제