Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is let not a valid recur target?

Tags:

clojure

In clojure, this is valid:

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

However, this is not:

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

So I'm wondering: why are loop and let separated, given the fact they both (at least conceptually) introduce lexical bindings? That is, why is loop a recur target while let is not?

EDIT: originally wrote "loop target" which I noticed is incorrect.

like image 710
jjpe Avatar asked Oct 04 '13 10:10

jjpe


1 Answers

Consider the following example:

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

This function calculates n+mth line of pascal triangle by given mth line.

Now, imagine, that let is a recur target. In this case I won't be able to recursively call the pascal-step function itself from let binding using recur operator.

Now let's make this example a little bit more complex:

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

Now we're calculating nth line of a pascal triangle. As you can see, I need both loop and let here.

This example is quite simple, so you may suggest removing let binding by using (concat v [0]) and (cons 0 v) directly, but I'm just showing you the concept. There may be a more complex examples where let inside a loop is unavoidable.

like image 102
Leonid Beschastny Avatar answered Oct 10 '22 00:10

Leonid Beschastny