2009-07-22 2 views
6

a-list에 나타나는 an-element 횟수를 세는 함수를 작성했습니다. 나는 다양한 입력을 시도해 보았지만 그 프로파일을 만들었지 만 스택 사용 효율과 시간 효율성면에서 어떤 기능이 가장 좋은지 아직 알지 못합니다. 제발 도와주세요. 컴파일러/interperter이 꼬리 재귀 위해 그것을 optmize 수스택 사용 효율 및 시간면에서 가장 좋은 함수는

;; Using an accumulator 
    (defn count-instances1 [a-list an-element] 
     (letfn [(count-aux [list-aux acc] 
         (cond 
          (empty? list-aux) acc 
          :else (if (= (first list-aux) an-element) 
            (count-aux (rest list-aux) (inc acc)) 
            (count-aux (rest list-aux) acc))))] 
     (count-aux a-list 0))) 

;; Normal counting 
    (defn count-instances2 [a-list an-element] 
    (cond 
     (empty? a-list) 0 
     :else 
      (if (= (first a-list) an-element) 
       (+ 1 (count-instances2 (rest a-list) an-element)) 
       (count-instances2 (rest a-list) an-element)))) 

;; using loop. does this help at all? 
    (defn count-instances3 [a-list an-element] 
     (loop [mylist a-list acount 0] 
      (if (empty? mylist) 
       acount 
       (if (= (first mylist) an-element) 
       (recur (rest mylist)(inc acount)) 
       (recur (rest mylist) acount))))) 
+3

프로파일 작업의 결과는 무엇입니까? –

+3

중첩 된'defn'은 아마도 당신이 생각하는 것을하지 않을 것입니다. 'defn'은 항상 최상위 함수를 정의합니다. 내부 함수를 정의하고 싶다면'letfn' (또는'(let [f (fn ...)])을 사용할 수 있습니다. –

+0

브라이언에게 감사드립니다. 하지만 나는 일할 수있는 letfn을 얻을 수 없습니다. Letfn으로 내 질문을 편집 할 수 있습니까? 고마워. – unj2

답변

2

루프/RECUR 버전 적당한 방법이다. Clojure는 JVM의 한계로 인해 꼬리 호출을 최적화 할 수 없습니다.

+3

정확하지 않습니다. Clojure *는 꼬리 호출을 최적화하지 않기로 선택해야한다고 말하면됩니다. 아직 호출을 최적화하지 않은 언어 (Java)에서는 달성하기가 매우 어렵 기 때문에 꼬리 호출을 최적화하지 않기로 결정했습니다. 실제로 꼬리 호출을 최적화하는 JVM 상단에 몇 가지 언어 구현 (예 : SISC - http://sisc-scheme.org/)이 있습니다. –

+0

정말 이상합니다. 꼬리표를 최적화하고 싶지 않은 이유는 무엇입니까? 그것은 우리에게 많은 번거 로움을 덜어 줬을 것입니까? 트레이드 오프가 있습니까? – unj2

+3

'recur'는 명시 적이기 때문에 꼬리 위치에서만 사용할 수 있습니다 (컴파일러는 별다른 불평을하지 않습니다). 자동으로 매크로를 사용할 수는 있지만 꼬리 호출에서 함수 이름을'recur' 심볼로 대체하는 것은별로 번거롭지 않습니다. –

0

코드를 작성, 약간의 성능 향상 결과 및 사용 감소를 스택해야한다. 나는 평범한 계산 기능이 꼬리 재귀를위한 자격이 될 수있어서 꽤 빨리해야한다고 생각한다. 나는 Lisp을 취미로 다루기 때문에 확신 할 수 없다.

http://en.wikipedia.org/wiki/Tail_recursion

+0

Clojure는 JVM의 제한으로 인해 꼬리 호출을 최적화 할 수 없습니다. – Svante

+1

풍부한 Hickey의 의견은 (JVM에서이 작업의 복잡성으로 인해) 거의 항상 작동하는 암시적인 것보다 항상 작동하는 명시적인 abstaction을 갖는 것이 더 낫다는 것이 었습니다. –

+0

@Svante - Clojure는 꼬리 호출을 최적화 할 수 있고 최적화합니다. 'recur' (Rich Hickey의 언어 디자인 선택)를 사용하여 원하는 것을 명시해야합니다. 대부분의 경우 JVM에서 TCO를 완벽하게 수행 할 수 있습니다. JVM 제한은 상호 공동 재귀에만 영향을줍니다 (실제로는 매우 드뭅니다). – mikera