implementing foreach (doseq) in clojure - recursion

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

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

How create fold-left with 2 arg?

How I can write a fold-left function with 2 parameters (foldl-1 proc xs)? This doesn't work:
(define (my-fold-left op xs)
(define (func proc start xs)
(let ((start xs))
(set! start (car xs))
(if (null? xs) start
(func op (op start (car xs)) (cdr xs))))))
Your code doesn't make sense... why use set! here? what is the initial value for the result? and why define the function func if you aren't going to call it? To implement a typical 3-arg fold-left try something like this, noticing that the main advantage of fold-left is that it's tail-recursive, and we use a parameter for accumulating the result:
(define (fold-left op ini xs)
(let loop ((acc ini) (lst xs))
(if (null? lst)
acc
(loop (op (car lst) acc) (cdr lst)))))
If you really need a 2-arg version of fold-left, remove the ini parameter and set a default value for acc at the beginning, in the second line. Be aware that by doing this you're restricting the usefulness of this procedure to return only a fixed type of results, depending on the initial value of your choosing.

What is "named let" and how do I use it to implement a map function?

I'm totally new to Scheme and I am trying to implement my own map function. I've tried to find it online, however all the questions I encountered were about some complex versions of map function (such as mapping functions that take two lists as an input).
The best answer I've managed to find is here: (For-each and map in Scheme). Here is the code from this question:
(define (map func lst)
(let recur ((rest lst))
(if (null? rest)
'()
(cons (func (car rest)) (recur (cdr rest))))))
It doesn't solve my problem though because of the usage of an obscure function recur. It doesn't make sense to me.
My code looks like this:
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
I do understand the logic behind the functional approach when programming in this language, however I've been having great difficulties with coding it.
The first code snippet you posted is indeed one way to implement the map function. It uses a named let. See my comment on an URL on how it works. It basically is an abstraction over a recursive function. If you were to write a function that prints all numbers from 10 to 0 you could write it liks this
(define (printer x)
(display x)
(if (> x 0)
(printer (- x 1))))
and then call it:
(printer 10)
But, since its just a loop you could write it using a named let:
(let loop ((x 10))
(display x)
(if (> x 0)
(loop (- x 1))))
This named let is, as Alexis King pointed out, syntactic sugar for a lambda that is immediately called. The above construct is equivalent to the snippet shown below.
(letrec ((loop (lambda (x)
(display x)
(if (> x 0)
(loop (- x 1))))))
(loop 10))
In spite of being a letrec it's not really special. It allows for the expression (the lambda, in this case) to call itself. This way you can do recursion. More on letrec and let here.
Now for the map function you wrote, you are almost there. There is an issue with your two last cases. If the list is not empty you want to take the first element, apply your function to it and then apply the function to the rest of the list. I think you misunderstand what you actually have written down. Ill elaborate.
Recall that a conditional clause is formed like this:
(cond (test1? consequence)
(test2? consequence2)
(else elsebody))
You have any number of tests with an obligatory consequence. Your evaluator will execute test1? and if that evaluated to #t it will execute the consequence as the result of the entire conditional. If test1? and test2? fail it will execute elsebody.
Sidenote
Everything in Scheme is truthy except for #f (false). For example:
(if (lambda (x) x)
1
2)
This if test will evaluate to 1 because the if test will check if (lambda (x) x) is truthy, which it is. It is a lambda. Truthy values are values that will evaluate to true in an expression where truth values are expected (e.g., if and cond).
Now for your cond. The first case of your cond will test if L is null. If that is evaluated to #t, you return the empty list. That is indeed correct. Mapping something over the empty list is just the empty list.
The second case ((f (car L))) literally states "if f is true, then return the car of L".
The else case states "otherwise, return the result mymap on the rest of my list L".
What I think you really want to do is use an if test. If the list is empty, return the empty list. If it is not empty, apply the function to the first element of the list. Map the function over the rest of the list, and then add the result of applying the function the first element of the list to that result.
(define (mymap f L)
(cond ((null? L) '())
(f (car L))
(else (mymap (f (cdr L))))))
So what you want might look look this:
(define (mymap f L)
(cond ((null? L) '())
(else
(cons (f (car L))
(mymap f (cdr L))))))
Using an if:
(define (mymap f L)
(if (null? L) '()
(cons (f (car L))
(mymap f (cdr L)))))
Since you are new to Scheme this function will do just fine. Try and understand it. However, there are better and faster ways to implement this kind of functions. Read this page to understand things like accumulator functions and tail recursion. I will not go in to detail about everything here since its 1) not the question and 2) might be information overload.
If you're taking on implementing your own list procedures, you should probably make sure they're using a proper tail call, when possible
(define (map f xs)
(define (loop xs ys)
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys))))
(loop (reverse xs) empty))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)
Or you can make this a little sweeter with the named let expression, as seen in your original code. This one, however, uses a proper tail call
(define (map f xs)
(let loop ([xs (reverse xs)] [ys empty])
(if (empty? xs)
ys
(loop (cdr xs) (cons (f (car xs)) ys)))))
(map (λ (x) (* x 10)) '(1 2 3 4 5))
; => '(10 20 30 40 50)

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)

Recursion over a list of s-expressions in Clojure

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

Resources