Search code examples
clojuretail-recursion

How to rewrite this function to be tail-recursive?


I'm reading the book The Little Schemer, I implement the functions in Clojure, How to rewrite this function as a tail-recursive function in Clojure?

(defn rember*
    [a lat]
    (cond
        (empty? lat) []
        (clojure.inspector/atom? (first lat))
            (if (= a (first lat))
                (rember* a (rest lat))
                (cons (first lat)
                      (rember* a (rest lat))))
        :else
            (cons (rember* a (first lat))
                  (rember* a (rest lat)))))

Solution

  • Here is a translation of your code to a version that uses a loop and two lists instead of recursion in order to maintain program state:

    (defn rember* [a lat]
      (loop [[[op-type a lat] & rest-ops] (list [:rember a lat])
             data '()]
        (case op-type
          nil (first data)
          :value (recur rest-ops (cons a data))
          :rember (cond
                    (empty? lat) (recur rest-ops (cons '() data))
                    
                    (clojure.inspector/atom? (first lat))
                    (if (= a (first lat))
                      (recur (cons [:rember a (rest lat)] rest-ops) data)
                      (recur (into rest-ops [[:cons]
                                             [:rember a (rest lat)]
                                             [:value (first lat)]])
                             data))
                    :else (recur (into rest-ops [[:cons]
                                                 [:rember a (rest lat)]
                                                 [:rember a (first lat)]])
                                 data))
          :cons (let [[a b & data] data]
                  (recur rest-ops (cons (cons b a) data))))))