Recursion over a list of s-expressions in Clojure - recursion

To set some context, I'm in the process of learning Clojure, and Lisp development more generally. On my path to Lisp, I'm currently working through the "Little" series in an effort to solidify a foundation in functional programming and recursive-based solution solving. In "The Little Schemer," I've worked through many of the exercises, however, I'm struggling a bit to convert some of them to Clojure. More specifically, I'm struggling to convert them to use "recur" so as to enable TCO. For example, here is a Clojure-based implementation to the "occurs*" function (from Little Schemer) which counts the number of occurrences of an atom appearing within a list of S-expressions:
(defn atom? [l]
(not (list? l)))
(defn occurs [a lst]
(cond
(empty? lst) 0
(atom? (first lst))
(cond
(= a (first lst)) (inc (occurs a (rest lst)))
true (occurs a (rest lst)))
true (+ (occurs a (first lst))
(occurs a (rest lst)))))
Basically, (occurs 'abc '(abc (def abc) (abc (abc def) (def (((((abc))))))))) will evaluate to 5. The obvious problem is that this definition consumes stack frames and will blow the stack if given a list of S-expressions too deep.
Now, I understand the option of refactoring recursive functions to use an accumulator parameter to enable putting the recursive call into the tail position (to allow for TCO), but I'm struggling if this option is even applicable to situations such as this one.
Here's how far I get if I try to refactor this using "recur" along with using an accumulator parameter:
(defn recur-occurs [a lst]
(letfn [(myoccurs [a lst count]
(cond
(empty? lst) 0
(atom? (first lst))
(cond
(= a (first lst)) (recur a (rest lst) (inc count))
true (recur a (rest lst) count))
true (+ (recur a (first lst) count)
(recur a (rest lst) count))))]
(myoccurs a lst 0)))
So, I feel like I'm almost there, but not quite. The obvious problem is my "else" clause in which the head of the list is not an atom. Conceptually, I want to sum the result of recurring over the first element in the list with the result of recurring over the rest of the list. I'm struggling in my head on how to refactor this such that the recurs can be moved to the tail position.
Are there additional techniques to the "accumulator" pattern to achieving getting your recursive calls put into the tail position that I should be applying here, or, is the issue simply more "fundamental" and that there isn't a clean Clojure-based solution due to the JVM's lack of TCO? If the latter, generally speaking, what should be the general pattern for Clojure programs to use that need to recur over a list of S-expressions? For what it's worth, I've seen the multi method w/lazy-seq technique used (page 151 of Halloway's "Programming Clojure" for reference) to "Replace Recursion with Laziness" - but I'm not sure how to apply that pattern to this example in which I'm not attempting to build a list, but to compute a single integer value.
Thank you in advance for any guidance on this.

Firstly, I must advise you to not worry much about implementation snags like stack overflows as you make your way through The Little Schemer. It is good to be conscientious of issues like the lack of tail call optimization when you're programming in anger, but the main point of the book is to teach you to think recursively. Converting the examples accumulator-passing style is certainly good practice, but it's essentially ditching recursion in favor of iteration.
However, and I must preface this with a spoiler warning, there is a way to keep the same recursive algorithm without being subject to the whims of the JVM stack. We can use continuation-passing style to make our own stack in the form of an extra anonymous function argument k:
(defn occurs-cps [a lst k]
(cond
(empty? lst) (k 0)
(atom? (first lst))
(cond
(= a (first lst)) (occurs-cps a (rest lst)
(fn [v] (k (inc v))))
:else (occurs-cps a (rest lst) k))
:else (occurs-cps a (first lst)
(fn [fst]
(occurs-cps a (rest lst)
(fn [rst] (k (+ fst rst))))))))
Instead of the stack being created implicitly by our non-tail function calls, we bundle up "what's left to do" after each call to occurs, and pass it along as the next continuation k. When we invoke it, we start off with a k that represents nothing left to do, the identity function:
scratch.core=> (occurs-cps 'abc
'(abc (def abc) (abc (abc def) (def (((((abc))))))))
(fn [v] v))
5
I won't go further into the details of how to do CPS, as that's for a later chapter of TLS. However, I will note that this of course doesn't yet work completely:
scratch.core=> (def ls (repeat 20000 'foo))
#'scratch.core/ls
scratch.core=> (occurs-cps 'foo ls (fn [v] v))
java.lang.StackOverflowError (NO_SOURCE_FILE:0)
CPS lets us move all of our non-trivial, stack-building calls to tail position, but in Clojure we need to take the extra step of replacing them with recur:
(defn occurs-cps-recur [a lst k]
(cond
(empty? lst) (k 0)
(atom? (first lst))
(cond
(= a (first lst)) (recur a (rest lst)
(fn [v] (k (inc v))))
:else (recur a (rest lst) k))
:else (recur a (first lst)
(fn [fst]
(recur a (rest lst) ;; Problem
(fn [rst] (k (+ fst rst))))))))
Alas, this goes wrong: java.lang.IllegalArgumentException: Mismatched argument count to recur, expected: 1 args, got: 3 (core.clj:39). The very last recur actually refers to the fn right above it, the one we're using to represent our continuations! We can get good behavior most of the time by changing just that recur to a call to occurs-cps-recur, but pathologically-nested input will still overflow the stack:
scratch.core=> (occurs-cps-recur 'foo ls (fn [v] v))
20000
scratch.core=> (def nested (reduce (fn [onion _] (list onion))
'foo (range 20000)))
#'scratch.core/nested
scratch.core=> (occurs-cps-recur 'foo nested (fn [v] v))
Java.lang.StackOverflowError (NO_SOURCE_FILE:0)
Instead of making the call to occurs-* and expecting it to give back an answer, we can have it return a thunk immediately. When we invoke that thunk, it'll go off and do some work right up until it does a recursive call, which in turn will return another thunk. This is trampolined style, and the function that "bounces" our thunks is trampoline. Returning a thunk each time we make a recursive call bounds our stack size to one call at a time, so our only limit is the heap:
(defn occurs-cps-tramp [a lst k]
(fn []
(cond
(empty? lst) (k 0)
(atom? (first lst))
(cond
(= a (first lst)) (occurs-cps-tramp a (rest lst)
(fn [v] (k (inc v))))
:else (occurs-cps-tramp a (rest lst) k))
:else (occurs-cps-tramp a (first lst)
(fn [fst]
(occurs-cps-tramp a (rest lst)
(fn [rst] (k (+ fst rst)))))))))
(declare done answer)
(defn my-trampoline [th]
(if done
answer
(recur (th))))
(defn empty-k [v]
(set! answer v)
(set! done true))
(defn run []
(binding [done false answer 'whocares]
(my-trampoline (occurs-cps-tramp 'foo nested empty-k))))
;; scratch.core=> (run)
;; 1
Note that Clojure has a built-in trampoline (with some limitations on the return type). Using that instead, we don't need a specialized empty-k:
scratch.core=> (trampoline (occurs-cps-tramp 'foo nested (fn [v] v)))
1
Trampolining is certainly a cool technique, but the prerequisite to trampoline a program is that it must contain only tail calls; CPS is the real star here. It lets you define your algorithm with the clarity of natural recursion, and through correctness-preserving transformations, express it efficiently on any host that has a single loop and a heap.

You can't do this with a fixed amount of memory. You can consume stack, or heap; that's the decision you get to make. If I were writing this in Clojure I would do it with map and reduce rather than with manual recursion:
(defn occurs [x coll]
(if (coll? coll)
(reduce + (map #(occurs x %) coll))
(if (= x coll)
1, 0)))
Note that shorter solutions exist if you use tree-seq or flatten, but at that point most of the problem is gone so there's not much to learn.
Edit
Here's a version that doesn't use any stack, instead letting its queue get larger and larger (using up heap).
(defn heap-occurs [item coll]
(loop [count 0, queue coll]
(if-let [[x & xs] (seq queue)]
(if (coll? x)
(recur count (concat x xs))
(recur (+ (if (= item x) 1, 0)
count)
xs))
count)))

Related

Rewriting a common function using tail-end recursion

I've been trying to tinker with this code to rewrite a "repeat" function using tail-end recursion but have gotten a bit stuck in my attempts.
(define (repeat n x)
(if (= n 0)
'()
(cons x (repeat (- n 1) x))))
This is the original "repeat" function. It traverses through 'n - 1' levels of recursion then appends 'x' into a list in 'n' additional recursive calls. Instead of that, the recursive call should be made and the 'x' should be appended to a list at the same time.
(define (repeat-tco n x)
(trace-let rec ([i 0]
[acc '()])
(if (= i n)
acc
(rec (+ i 1) (cons x acc)))))
This is the closest rewritten version that I've come up with which I believe follows tail-call recursion but I'm not completely sure.
Your repeat-tco function is indeed tail recursive: it is so because the recursive call to rec is in 'tail position': at the point where it's called, the function that is calling it has nothing left to do but return the value of that call.
[The following is just some perhaps useful things: the answer is above, but an answer which was essentially 'yes' seemed too short.]
This trick of taking a procedure p which accumulates some result via, say (cons ... (p ...)) and turning it into a procedure with an extra 'accumulator' argument which is then tail recursive is very common. A result of using this technique is that the results come out backwards: this doesn't matter for you because all the elements of your list are the same, but imagine this:
(define (evens/backwards l)
(let loop ([lt l]
[es '()])
(if (null? lt)
es
(loop (rest lt)
(if (even? (first lt))
(cons (first lt) es)
es)))))
This will return the even elements of its arguments, but backwards. If you want them the right way around, a terrible answer is
(define (evens/terrible l)
(let loop ([lt l]
[es '()])
(if (null? lt)
es
(loop (rest lt)
(if (even? (first lt))
(append es (list (first lt)))
es)))))
(Why is it a terrible answer?) The proper answer is
(define (evens l)
(let loop ([lt l]
[es '()])
(if (null? lt)
(reverse es)
(loop (rest lt)
(if (even? (first lt))
(cons (first lt) es)
es)))))

Iterative map in scheme

I am watching SICP video lectures and i came to a section where tutors are showing procedures to work with lists, so, here is one of them:
(define (map p l)
(if (null? l)
(list)
(cons (p (car l))
(map p (cdr l)))))
What i want to ask is: is there a way to define map in iterative way, or that cons requires lazy evaluation to be executed right?
You original code is almost tail recursive.. the only thing that makes it not is the cons part. If Scheme had equal requirement for having TRMC optimization as it has TCO requirement you could leave your code as is and the implementation would have made it tail recursive for you.
Since it isn't a requirement we need to do our own TRMC optimization. Usually when iterating a list in a loop and having it tail recursive by using an accumulator you get the result in the opposite order, thus you can do linear update reverse:
(define (map proc lst)
(let loop ((lst lst) (acc '()))
(cond ((null? lst) (reverse! acc) acc)
(else (loop (cdr lst)
(cons (proc (car lst)) acc))))))
Or you can do it all in one pass:
(define (map proc lst)
(define head (list 1))
(let loop ((tail head) (lst lst))
(cond ((null? lst) (cdr head))
(else (set-cdr! tail (list (proc (car lst))))
(loop (cdr tail) (cdr lst))))))
Now in both cases you mutate only the structure the procedure has itself created, thus for the user it might as well be implemented in the same manner as your example.
When you use higher order procedures like map from your implementation it could happen it has been implemented like this. It's easy to find out by comparing performance on the supplied map with the different implementations with a very long list. The difference between the executions would tell you if it's TRMCO or how the supplied map probably has been implemented.
You need to embrace recursion in order to appreciate SICP and Scheme in general, so try to get used to it, you will appreciate it later, promised.
But yes, you can:
(define (iterative-map f lst)
(define res null)
(do ((i (- (length lst) 1) (- i 1))) ((= i -1))
(set! res (cons (f (list-ref lst i)) res)))
res)
(iterative-map (lambda (x) (+ x 1)) '(1 3 5))
=> '(2 4 6)
but using set! is considered bad style if avoidable.
In Racket you have a different set of loops that are more elegant:
(define (for-map f lst)
(for/list ((i lst))
(f i)))
(for-map add1 '(1 3 5))
=> '(2 4 6)

implementing foreach (doseq) in clojure

i'm working through SICP - one exercise is to implement foreach (doseq). This is an academic exercise. In clojure, this is what I came up with:
(defn for-each [proc, items]
(if (empty? items) nil
(do
(proc (first items))
(recur proc (rest items)))))
but, i'm a little murky about if do is cheating, because do is a special form in clojure and i don't think anything like that has been introduced yet in SICP. is there a more minimalist answer?
Here's another attempt which only executes proc on the last element:
(defn for-each-2 [proc, items]
(let [f (first items)
r (rest items)]
(if (empty? r)
(proc f)
(recur proc r))))
Use doseq and you're all set. For example:
(doseq [e '(1 2 3)]
(prn e))
Will print:
1
2
3
nil
EDIT :
If you want to implement for-each by hand and using as few special forms as possible, here's another alternative, although it ends up being almost as short as yours:
(defn for-each [f l]
(cond (empty? l) nil
:else (do (f (first l))
(recur f (rest l)))))
Interestingly, the same procedure could have been written more succinctly in Scheme, the Lisp dialect used in SICP:
(define (for-each f l)
(cond ((null? l) null)
(else (f (first l))
(for-each f (rest l)))))
Here is my attempt. It just carries function execution in an inner loop.
(defn for-each [fun, xs]
(loop [fun fun
xs xs
action nil]
(if (first xs)
(recur fun (rest xs) (fun (first xs)))
xs)))

Maximum of a list using recursion?

My task is to write function in lisp which finds maximum of a list given as argument of the function, by using recursion.I've tried but i have some errors.I'm new in Lisp and i am using cusp plugin for eclipse.This is my code:
(defun maximum (l)
(if (eq((length l) 1)) (car l)
(if (> (car l) (max(cdr l)))
(car l)
(max (cdr l))
))
If this isn't a homework question, you should prefer something like this:
(defun maximum (list)
(loop for element in list maximizing element))
Or even:
(defun maximum (list)
(reduce #'max list))
(Both behave differently for empty lists, though)
If you really need a recursive solution, you should try to make your function more efficient, and/or tail recursive. Take a look at Diego's and Vatine's answers for a much more idiomatic and efficient recursive implementation.
Now, about your code:
It's pretty wrong on the "Lisp side", even though you seem to have an idea as to how to solve the problem at hand. I doubt that you spent much time trying to learn lisp fundamentals. The parentheses are messed up -- There is a closing parenthesis missing, and in ((length l) 1), you should note that the first element in an evaluated list will be used as an operator. Also, you do not really recurse, because you're trying to call max (not maximize). Finally, don't use #'eq for numeric comparison. Also, your code will be much more readable (not only for others), if you format and indent it in the conventional way.
You really should consider spending some time with a basic Lisp tutorial, since your question clearly shows lack of understanding even the most basic things about Lisp, like the evaluation rules.
I see no answers truly recursive and I've written one just to practice Common-Lisp (currently learning). The previous answer that included a recursive version was inefficient, as it calls twice maximum recursively. You can write something like this:
(defun my-max (lst)
(labels ((rec-max (lst actual-max)
(if (null lst)
actual-max
(let ((new-max (if (> (car lst) actual-max) (car lst) actual-max)))
(rec-max (cdr lst) new-max)))))
(when lst (rec-max (cdr lst) (car lst)))))
This is (tail) recursive and O(n).
I think your problem lies in the fact that you refer to max instead of maximum, which is the actual function name.
This code behaves correctly:
(defun maximum (l)
(if (= (length l) 1)
(car l)
(if (> (car l) (maximum (cdr l)))
(car l)
(maximum (cdr l)))))
As written, that code implies some interesting inefficiencies (it doesn't have them, because you're calling cl:max instead of recursively calling your own function).
Function calls in Common Lisp are typically not memoized, so if you're calling your maximum on a long list, you'll end up with exponential run-time.
There are a few things you can do, to improve the performance.
The first thing is to carry the maximum with you, down the recursion, relying on having it returned to you.
The second is to never use the idiom (= (length list) 1). That is O(n) in list-length, but equivalent to (null (cdr list)) in the case of true lists and the latter is O(1).
The third is to use local variables. In Common Lisp, they're typically introduced by let. If you'd done something like:
(let ((tail-max (maximum (cdr l))))
(if (> (car l) tail-max)
(car l)
tail-max))
You would've had instantly gone from exponential to, I believe, quadratic. If in combination had done the (null (cdr l)) thing, you would've dropped to O(n). If you also had carried the max-seen-so-far down the list, you would have dropped to O(n) time and O(1) space.
if i need to do the max code in iteration not recursive how the code will be ??
i first did an array
(do do-array (d l)
setf b (make-array (length d))
(do (((i=0)(temp d))
((> i (- l 1)) (return))
(setf (aref b i) (car temp))
(setq i (+ i 1))
(setq temp (cdr temp))))
I made this, hope it helps and it is recursive.
(defun compara ( n lista)
(if(endp lista)
n
(if(< n (first lista))
nil
(compara n (rest lista)))))
(defun max_lista(lista)
(if (endp lista)
nil
(if(compara (first lista) (rest lista))
(first lista)
(max_lista(rest lista)))))
A proper tail-recursive solution
(defun maximum (lst)
(if (null lst)
nil
(maximum-aux (car lst) (cdr lst))))
(defun maximum-aux (m lst)
(cond
((null lst) m)
((>= m (car lst)) (maximum-aux m (cdr lst)))
(t (maximum-aux (car lst) (cdr lst)))))
(defun maxx (l)
(if (null l)
0
(if(> (car l) (maxx(cdr l)))
(car l)
(maxx (cdr l)))))

Which Function is the best in terms of Stack Usage Efficiency and Time

I wrote 3 functions that count the number of times an-element appears in a-list.
I tried various inputs and profiled it but I still dont know which function is the best in terms of stack usage efficiency and time efficiency. Please Help me out.
;; Using an accumulator
(defn count-instances1 [a-list an-element]
(letfn [(count-aux [list-aux acc]
(cond
(empty? list-aux) acc
:else (if (= (first list-aux) an-element)
(count-aux (rest list-aux) (inc acc))
(count-aux (rest list-aux) acc))))]
(count-aux a-list 0)))
;; Normal counting
(defn count-instances2 [a-list an-element]
(cond
(empty? a-list) 0
:else
(if (= (first a-list) an-element )
(+ 1 (count-instances2 (rest a-list) an-element))
(count-instances2 (rest a-list) an-element))))
;; using loop. does this help at all?
(defn count-instances3 [a-list an-element]
(loop [mylist a-list acount 0]
(if (empty? mylist)
acount
(if (= (first mylist) an-element)
(recur (rest mylist)(inc acount))
(recur (rest mylist) acount)))))
The loop/recur version is the right way. Clojure cannot optimize tail calls due to limitations of the JVM.
Writing your code so the compiler/interperter can optmize it for tail recursion, should result in some performance increase and stack usage reduction. I think your normal counting function could qualifies for tail recursion so that one should be pretty fast. Not sure since I only dabble in Lisp as a hobby.
http://en.wikipedia.org/wiki/Tail_recursion

Resources