2013-10-04 14 views
6

、これが有効である:なぜ有効な再帰ターゲットはありませんか? Clojureので

(loop [a 5] 
    (if (= a 0) 
    "done" 
    (recur (dec a)))) 

はしかし、これではありません。

(let [a 5] 
    (if (= a 0) 
    "done" 
    (recur (dec a)))) 

は、だから私は思ったんだけど:なぜ彼らは両方(少なくとも事実を考えると、ループであり、分離してみましょう概念的に)字句バインディングを導入していますか?つまり、letはループしていないのに対し、loopは繰り返しターゲットですか?

EDIT:もともと私が気づいた "loop target"は間違っています。

答えて

5

次の例を考えてみます。

(defn pascal-step [v n] 
    (if (pos? n) 
     (let [l (concat v [0]) 
      r (cons 0 v)] 
     (recur (map + l r) (dec n))) 
     v)) 

この関数は、指定されたm番目のラインによってパスカルの三角形のn+m番目の行を計算します。

ここで、letrecurのターゲットであるとします。この場合、recur演算子を使用してletバインディングからpascal-step関数自体を再帰的に呼び出すことはできません。

今度はもう少し複雑なこの例を作成してみましょう:

(defn pascal-line [n] 
    (loop [v [1] 
     i n] 
    (if (pos? i) 
     (let [l (concat v [0]) 
       r (cons 0 v)] 
      (recur (map + l r) (dec i))) 
     v))) 

今、私たちは、パスカル三角形のn番目の行を計算しています。ご覧のとおり、loopletの両方が必要です。

この例は非常に単純なので、(concat v [0])(cons 0 v)を直接使用してletバインディングを削除することをおすすめしますが、私はあなたにその概念を示しています。 loopの中のletが避けられないより複雑な例があるかもしれません。

+1

よろしくお願いします。しかし、ジャンプするターゲットを指定する余分なオプションのargをなぜ再現しないのでしょうか?または、それはgotoの方向にあまりにも多くなるでしょう(そして、私たちは皆、Dijkstraがgotosについて何を言ったのか知っています)? – jjpe

+4

@jjpeはループがあるので、再帰ターゲットではありません。 letが再帰ターゲットだった場合、ループは存在しませんでした。ループはletとまったく同じですが、反復ターゲットとしても機能します。 http://clojure.org/special_forms#loopを参照してください。 –