Clojure recursion, loop/recur.


;;; Clojure recursion
(defn every-other [coll]
  (if (empty? coll)
      '()
      (conj (every-other (rest (rest coll))) (first coll))))

(every-other '(2 3 4))
(every-other [])
(every-other [2])
(every-other (take 10 (range)))

;; You can write this in tail-recursive fashion:
(defn every-other2 [coll result]
  (if (empty? coll)
      result
      (every-other2 (rest (rest coll)) (conj result (first coll)))))

(every-other2 '(2 3 4) '())
(every-other2 [] '())
(every-other2 [2] '())
(every-other2 (take 10 (range)) '())

;; However, Java doesn't optimize tail recursion
;; Clojure has a loop-recur form for tail recursion:
(defn every-other-loop [coll]
  (loop [c coll r '()]
    (if (empty? c)
        r
        (recur (rest (rest c)) (conj r (first c))))))

;; This is almost correct, except the order is reversed (why?)
(every-other-loop '(2 3 4))
(every-other-loop [])
(every-other-loop [2])
(every-other-loop (take 10 (range)))

;; Passing [] as initial value for r in loop/recur
;; changes the order of adding elements via conj
(defn every-other-loop2 [coll]
  (loop [c coll r []]
    (if (empty? c)
        r
        (recur (rest (rest c)) (conj r (first c))))))

;; This is almost correct, except the order os reversed (why?)
(every-other-loop2 '(2 3 4))
(every-other-loop2 [])
(every-other-loop2 [2])
(every-other-loop2 (take 10 (range)))

CSci 4651 course web site.