2017-01-07 12 views
2

나는 Clojure와 SICP를 배우기 위해 SICP를 Clojure로 번역 할 것입니다. 현재, 2.2.2 절의 Count Leaves 절차에 문제가 있습니다.Clojure에서 count-leaves in SICP

목표는 트리의 목록 표현을 취하는 함수를 작성하는 것입니다. '(1 2'(3 4))과 4

지금까지이 경우 잎의 수를 계산, 나는 함께 온 가장 가까운 그러나

(defn count-leaves 
    [coll] 
    (cond 
    (nil? coll) 0 
    (not (seq? coll)) 1 
    :else (let [[left & right] coll] (+ (count-leaves left) (count-leaves right))) 
    )) 

,이 처리하지 않습니다이다 하위 트리를 올바르게 특히,

구성표 구현 from the book이 주
(count-leaves '('(1))) 

2 대신 1

평가 : 한 언어에서 다른 언어로

(define (count-leaves x) 
    (cond ((null? x) 0) 
     ((not (pair? x)) 1) 
     (else (+ (count-leaves (car x)) 
       (count-leaves (cdr x)))))) 
+2

"... (count-leaves '('(1))) ~을 2 ..."로 평가합니다 ... - 그렇게해야합니다. ''('(1))'은 ((quote (1)))'로 평가됩니다. 이미 인용 된 목록 안에 하위 목록을 인용하지 마십시오. – jkiiski

+0

감사합니다. '('(1))이 (list (list 1))와 동일하지만 분명히 틀렸다고 생각했습니다. 추가 정보 : http://stackoverflow.com/questions/38515614/clojure-list-inside-list-declaration – Sven

답변

2

코멘트

은 당신의 코드가 작동, 제안합니다. 그래서 문제는 없습니다.

하지만 인수가 먼저 시퀀스인지 테스트하는 것이 좋습니다. (count-leaves '())0으로 평가되는 방식을 시도해보십시오! 내가 대신 destructuring에 내재 nextrest을 사용했습니다

스위치에게 cond의 첫 두 절 우리가 얻을 ...

(defn count-leaves [coll] 
    (cond 
    (not (seq? coll)) 1 
    (empty? coll) 0 
    :else (+ (count-leaves (first coll)) (count-leaves (rest coll))))) 

... 그래서 empty? 대신 nil?의 테스트하기 그것. 이 코드는 nil 값을 올바르게 처리합니다. 그러나 여전히 적절하게 재귀 적이므로 스택 오버 플로우가 발생할 수 있습니다.

선호 ...

(defn count-leaves [coll] 
    (if (seq? coll) 
    (apply + (map count-leaves coll)) 
    1)) 

... 여전히 재귀 적이지만 깨끗합니다.


내가 @glts's solution의 나의 좋은 의견을 철회 했어

편집 : postwalk 그래서 진짜 이점을 제공하지 재귀입니다.

2

번역의 예는 좋은 운동이지만, 할 언어에는 자체 관용구와 자체 핵심 라이브러리가 함께 제공된다는 점을 명심하십시오.

Clojure에서 워킹 데이터 구조는 특히 clojure.walk에서 쉽게 나타납니다.

clojure.walk을 요구하면 당신은 당신의 데이터 구조를 통과하는 방법을 볼 수 postwalk-demo을 실행할 수 있습니다

(require '[clojure.walk :refer [postwalk postwalk-demo]]) 
(postwalk-demo '(1 2 (3 4))) 
Walked: 1 
Walked: 2 
Walked: 3 
Walked: 4 
Walked: (3 4) 
Walked: (1 2 (3 4)) 

그런 다음 당신은 잎 노드를 계산하고 postwalk에 전달하는 기능을 고안 할 수 있습니다.

(postwalk (fn [e] 
      (if (seq? e) (apply + e) 1)) 
      '(1 2 (3 4))) 

포스트 워크 트래버스 리프 노드는 1로 대체되고 seqs는 구성하는 리프 수의 합계로 대체됩니다.

나는 이것이 접선 응답이라는 것을 알고 있지만 아마 아직도 유용하다는 것을 알게 될 것입니다. @ jkiski의 주석으로