2013-10-04 2 views
6

В Clojure, это справедливо:Почему не допустима повторная цель?

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

Однако это не так:

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

Вот и мне интересно: почему цикл и пусть разделены, учитывая тот факт, что они оба (по крайней мере, концептуально) внедрять лексические привязки? То есть, почему цикл повторяется, а пусть нет?

EDIT: изначально была написана «цель цикла», которая, как я заметил, неверна.

ответ

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)) 

Эта функция вычисляет n+m ю строчку треугольника Паскаля по данной m-й линии.

Теперь представьте, что let - цель recur. В этом случае я не смогу рекурсивно вызывать функцию pascal-step с привязкой let с использованием оператора recur.

Теперь давайте сделаем этот пример немного сложнее:

(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 ю строчку в треугольнике Паскаля. Как вы можете видеть, мне нужны и loop, и let.

Этот пример довольно прост, поэтому вы можете предложить удалить привязку let с помощью (concat v [0]) и (cons 0 v) напрямую, но я просто покажу вам концепцию. Могут быть более сложные примеры, когда let внутри loop неизбежно.

+1

Хорошо, я вижу вашу точку зрения. Однако почему тогда не повторяется дополнительный аргумент arg, указывающий, к какой цели нужно перейти? Или это слишком сильно пойдет в сторону goto's (и мы все знаем, что сказал Дейкстра о gotos)? – jjpe

+4

@jjpe let не является повторной целью, потому что цикл есть. Если let был повторной целью, цикл не существовал бы. цикл точно такой же, как let, за исключением того, что он также действует как цель повтора. См. Http://clojure.org/special_forms#loop –

Смежные вопросы