I'd like to write the following ex:
(adjoin-set 2 (adjoin-set 8 (adjoin-set 4 (adjoin-set 3 (adjoin-set 7 (adjoin-set 5 '()))))))
recursively.
My other code is as follows (from Structure and Interpretation of Computer Programs, 2nd ed.)
(define (entry tree) (car tree))
(define (left-branch tree) (cadr tree))
(define (right-branch tree) (caddr tree))
(define (make-tree entry left right)
(list entry left right))
(define (adjoin-set x set)
(cond ((null? set) (make-tree x '() '()))
((= x (entry set)) set)
((< x (entry set))
(make-tree (entry set)
(adjoin-set x (left-branch set))
(right-branch set)))
((> x (entry set))
(make-tree (entry set)
(left-branch set)
(adjoin-set x (right-branch set))))))
So far I've tried the following:
(define (bst list)
(if (null? list) '())
(bst (adjoin-set (cdr list) '())))
This doesn't work. How could I make this work?
I'd like to follow a similar approach as when making the calls manually, i.e., (adjoin-set (car list) (next adjoint-set)).
First, rather than working a binary search tree for representing sets, I'll just use lists with no duplicate elements. The point is that we'll write a method to adjoin a single element, and then figure out how to call it with repeatedly with multiple values and get the final result. You'll still be able to apply this approach to your tree-based implementation.
Representing sets with lists containing no duplicates
If we represent sets by lists with no duplicates, then a single adjoin just takes an element and a list and returns the list if the element is already in the list, or a new list created from the new element and the old list, if the list doesn't contain it. So, adjoin isn't too hard:
(define (member? element list)
(cond
((null? list) #f)
((eqv? (car list) element) #t)
(else (member? element (cdr list)))))
(define (adjoin element set)
(if (member? element set)
set
(cons element set)))
This is counterpart of what you've already got with adjoin-set from SICP.
Performing more than one operation
Now, if you want to be able to adjoin a bunch of elements onto some initial value, you're performing a reduction, or fold. There are lots of variant implementations of reduce or fold (and foldr, foldl, etc.), but a quick and simple left-associative version is:
(define (reduce function list initial-value)
(if (null? list)
initial-value
(reduce function
(cdr list)
(function (car list) initial-value))))
Now, you can reduce your adjoin function over a list of elements of and get the final result:
(define (adjoin* elements set)
(reduce adjoin elements set))
Here are two examples that adjoin a bunch of elements to some preexisting sets. In the first case, the set is the empty set. In the second case, it's the set (1 2 3 4). Of course, to make this work with your code, those initial sets will need to be tree-based sets.
(display (adjoin* '(5 7 3 4 8 2) '()))
;;=> (2 8 4 3 7 5)
(display (adjoin* '(5 7 3 4 8 2) '(1 2 3 4)))
;;=> (8 7 5 1 2 3 4)
Related
I am super beginner. So don’t be surprise that my question is that easy.
I have following list (1 3 ((2))(7))
And I have to reconstruct that list just with the function cons.
I have no idea how to cons the third element of the list.
Maybe there is someone how could help me!
Thanks a lot!
(cons '1 (cons '3 (cons '(2) (cons '(7) nil))))
--> (1 3 (2) (7))
There are still missing some brackets. I have no idea to fix it.
We can write us a program to do it.
CL-USER 85 > (defun consify (expression)
(cond ((atom expression)
(typecase expression
(null expression)
(symbol (list 'quote expression))
(otherwise expression)))
(t
(list 'cons
(consify (first expression))
(consify (rest expression))))))
CONSIFY
Above returns the CONS expression.
CL-USER 86 > (consify '(1 3 ((2))(7)))
(CONS 1 (CONS 3 (CONS (CONS (CONS 2 NIL) NIL) (CONS (CONS 7 NIL) NIL))))
We can now evaluate the result from above:
CL-USER 87 > (eval (consify '(1 3 ((2))(7))))
(1 3 ((2)) (7))
Same with your other expression:
CL-USER 88 > (pprint (consify '((Fat Cat)
(In da ((House)) It)
(Might eat (the (treats))))))
(CONS (CONS 'FAT (CONS 'CAT NIL))
(CONS (CONS 'IN (CONS 'DA (CONS (CONS (CONS 'HOUSE NIL) NIL)
(CONS 'IT NIL))))
(CONS (CONS 'MIGHT
(CONS 'EAT (CONS (CONS 'THE
(CONS (CONS 'TREATS NIL)
NIL))
NIL)))
NIL)))
CL-USER 89 > (eval (consify '((Fat Cat)
(In da ((House)) It)
(Might eat (the (treats))))))
((FAT CAT) (IN DA ((HOUSE)) IT) (MIGHT EAT (THE (TREATS))))
The fix for your problem would be this: (please keep reading tho, this is not the final answer)
(cons '1 (cons '3 (cons (cons '(2) nil) (cons '(7) nil))))
You were really really close with your solution: (cons '1 (cons '3 (cons '(2) (cons '(7) nil)))) the thing was that, as you said, there was some parethesis missing on the 2. You managed to make (2) which is a list containing 2, but the goal was to make a ((2)) which means: A list containing a list containing 2. So we simply changed '(2) to (cons '(2) nil)
Now, that being said, i would consider the use of '(2) as cheating, since if you are allowed to use quotes, you could just do '(1 3 ((2)) (7)) or the equivalent (quote (1 3 ((2)) (7)))) and you are done. Clearly there is no challenge in that. So what you probably have to do is use ONLY cons without beign able to use quote at all, in that case the soluion would look like this:
(cons 1 (cons 3 (cons (cons (cons 2 nil) nil) (cons (cons 7 nil) nil))))
And this is a lot more pure, which is probably what you were assigned to do, this WOULD be a valid answer
We could even go extreme purist and replace nil with () (They both represent the empty list) and we get this
(cons 1 (cons 3 (cons (cons (cons 2 ()) ()) (cons (cons 7 ()) ()))))
Which really shows the beauty of "Everything is a list" which lisp has. But let's face it, that's overkill
Now, if something is still not clear, you might need to study a little bit more on what lists really ARE in lisp. I'm not the best person to explain this (I'm a programer, not a teacher) but i can try. I do recomend you to do a little bit of research on your own tho, that beign said:
Theory time!
Feel free to skip this whole if you fell you are solid on the theory
Cons is one of the fundamental building blocks of lisp, it's a very very simple concept, It's a container that holds two... things. What those things are is beyond the scope of what we need to know, but is a very intresting topic on its's own. The important point is that we can call cons on two things (Eg. two numbers) like this (cons 3 4) and the interpreter would print something that looks like this (3 . 4), you can get the first argument by calling car and the second one by calling cdr like this:
(car (cons 3 4)) ; 3
(cdr (cons 3 4)) ; 4
Well, i said that a cons can hold to things, not just numbers, for example we could hold a number and the empty list NIL like (cons nil 7) and as you might expect (car (cons nil 7)) indeed returns NIL
We can also place a cons inside another cons! like this (cons (cons 3 4) (cons 6 7)) Which you could think of like a tree with to branches (So a binary tree), and each one of them also having two branches, and ad the end of those is the node holding each of the numbers. We can still use car and cdr to get the left and right elements ((3 . 4) and (6 . 7) respectively)
Ok, that easy, a little bit too easy, how are we suposed to get lists by just being able to make pairs? The answer is abstraction! There is a concept in computer science called a Linked List. There are many ways to make it in a lot of programing languages, usually with pointers and stuff. The idea behind a Linked List is that you can encode a list of things a series of Nodes, one "node" is nothing more than a thing that hold a value, and a way to get the next node. We also need to encode the concept of "There ISN'T a next node, you reached the end of the list". And if you are clever enough, you can start to see how the pieces come together and allows you to construct a linked list using just cons.
If we wanted to make a linked list (Which i would simply call a "list") of numbers in lisp we can define nodes using cons. We can place a number as the first argument and the next node as the second argument. We can also denote the terminating node, that tells us that we are at the end of the list with nil, so if then next node is nil, that means we reached the end of the list
The boring example would then be a list containing one element which would look something like this
(cons 8 nil)
We could get the element in this node with car, which would return 8, and get the next node with cdr. In this case cdr will return NIL, which is the terminating node and that would signal that we are in the last node of the list
It's not very exiting, but it's all we need to model our linked list! Lets try making a list of two elements now
(cons 8 (cons 9 nil))
Same logic as before, we can get the value of the first node with car and we can get the next node with cdr which would return the (cons 9 nil). And we can get the value of that node with car and it's corresponding next node which is the terminator and we reached the end
And indeed, if you type (cons 8 (cons 9 nil)) into the interpreter, you will get the same result as if you were to type (list 8 9). Since behind the scenes the ARE the same thing
Lets make a few more examples:
What about a list that contains one list? for example, we learned how to do (8 9) but what about ((8 9))?
We could simply take our whole (cons 8 (cons 9 nil)) thing and place into another node (cons VALUE NEXT) where next is nil (There is no next element) and value is our whole list, resulting in: (cons (cons 8 (cons 9 nil)) nil). And indeed, the interpreter prints ((8 9))
Armed with this knowledge let's give another go at your exercise. But let's be more fundamental about it, we can see that is is a list of four elements (lets call them a b c and d). We can make a list of them by connecting 4 nodes so:
(cons a
(cons b
(cons c
(cons d nil)
)
)
)
now let's thing about what a b c and d are. We can tell a and be are just numbers so they can be replaced pretty easily like this
(cons 1
(cons 3
(cons c
(cons d nil)
)
)
)
d is also pretty easy, is just a list containing a single element, we made one of those already and it looks like this (const 7 nil) so we can replace that as well
(cons 1
(cons 3
(cons c
(cons (cons 7 nil) nil)
)
)
)
And finally c is the most complicated one, because it is a list holding a list, but we can handle that no problem, we simply make a list of a single element (cons VALUE nil) and replace value with another list of a single element (cons 2 nil) and replace value with it so we get (cons (cons 2 nil) nil). Which we can replace in our final answer to get:
(cons 1
(cons 3
(cons (cons (cons 2 nil) nil)
(cons (cons 7 nil) nil)
)
)
)
Or back in a single line:
(cons 1 (cons 3 (cons (cons (cons 2 nil) nil) (cons (cons 7 nil) nil) )))
And there we go! You probably get the drill now it's a very simple concept, but it has a LOT of implications, which take a while to wrap your head around, and when you eventually do it, you get a glimpse of the ultimate power of the lisp programing language
I'm new to Scheme and functional programming in general. Can someone explain this code — specifically what kons and knil are? The goal is to flatten a list of lists.
(define (fold1 kons knil lst)
(if (null? lst)
knil
(fold1 kons (kons (car lst) knil) (cdr lst))))
I'm fairly certain kons is a function as it's being applied to two arguments but still not totally sure about its functionality.
This is a (weird) fold
This is a generalized folding procedure. In Lisps, lists are represented by cons cells and the empty list, where each (proper) list is either the empty list (), or a cons cell whose car is an element of the list and whose cdr is the rest of the list. E.g., a list (1 2 3 4 5) can be produced by
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 '())))))
The fold1 function that you've shown:
(define (fold1 kons knil lst)
(if (null? lst)
knil
(fold1 kons (kons (car lst) knil) (cdr lst))))
is a a way of taking a list like the one shown above and transforming it to:
(kons 5 (kons 4 (kons 3 (kons 2 (kons 1 knil)))))
This is a fold. This is an efficient generalization of lots of operations. For instance, if you use 0 as knil and + as kons, you compute the sum of the elements in the list.
Usually folds are right or left associative. A proper left-associative fold would transform to
(kons (kons (kons (kons (kons knil 1) 2) 3) 4) 5)
which might be clearer when viewed with + and infix notation:
(((((0 + 1) + 2) + 3) + 4) + 5)
The right associative fold would become
(1 + (2 + (3 + (4 + (5 + 0)))))
The left associative fold can be more efficient because the natural implementation is tail recursive, and elements are consumed from the list in the order that they can be extracted from the list. E.g., in the proper left associatve example, (kons knil 1) can be evaluated first to produce some value v, and then, in the same stack space, (kons v 2) can be evaluated, and so on. The right associative method requires traversing to the end of the list first. A naïve implementation requires stack space proportional to the length of the list.
This fold1 mixes things up a bit, because it's processing the elements of the list in a left associative manner, but the order of the arguments to the combining function is reversed.
This type of definition can be used any time that you have a algebraic datatype. Since a list in Lisps is either the empty list, or an element and a list combined with cons, you can write a function that handles each of these cases, and produces a new value by “replacing” cons with a combination function and the empty list with some designated value.
Flattening a list of lists
So, if you've got a list of lists, e.g., ((a b) (c d) (e f)), it's constructed by
(cons '(a b) (cons '(c d) (cons '(e f) '())))
With a right associative fold, you transform it to:
(append '(a b) (append '(c d) (append '(e f) '())))
by using append for kons, and '() for knil. However, in this slightly mixed up fold, your structure will be
(kons '(e f) (kons '(c d) (kons '(a b) knil)))
so knil can still be '(), but kons will need to be a function that calls append, but swaps the argument order:
(define (flatten lists)
(fold1 (lambda (right left)
(append left right))
'()
lists))
And so we have:
(flatten '((a b) (c d) (e f)))
;=> (a b c d e f)
Flattening deeper lists of lists
Given that this is a folding exercise, I expected that the list of lists are nested only one layer deep. However, since we've seen how to implement a simple flatten
(define (flatten lists)
(fold1 (lambda (right left)
(append left right))
'()
lists))
we can modify this to make sure that deeper lists are flattened, too. The kons function now
(lambda (right left)
(append left right))
simply appends the two lists together. left is the already appended and flattened list that we've been building up. right is the new component that we're taking on now. If we make a call to flatten that, too, that should flatten arbitrarily nested lists:
(define (flatten lists)
(fold1 (lambda (right left)
(append left (flatten right))) ; recursively flatten sublists
'()
lists))
This is almost right, except that now when we call (flatten '((a b) (c d))), we'll end up making a call to (flatten '(a b)), which will in turn make a call to (flatten 'a), but flatten is a wrapper for fold1, and fold1 expects its arguments to be lists. We need to decide what to do when flatten is called with a non-list. A simple approach is to have it return a list containing the non-list argument. That return value will mesh nicely with the append that's receiving the value.
(define (flatten lists) ; lists is not necessarily a list of lists anymore,
(if (not (pair? lists)) ; perhaps a better name should be chosen
(list lists)
(fold1 (lambda (right left)
(append left (flatten right)))
'()
lists)))
Now we have
(flatten '(a (b (c)) (((d)))))
;=> (a b c d)
The procedure shown is an implementation of fold:
In functional programming, fold – also known variously as reduce, accumulate, aggregate, compress, or inject – refers to a family of higher-order functions that analyze a recursive data structure and recombine through use of a given combining operation the results of recursively processing its constituent parts, building up a return value
Take note:
The kons parameter is a two-argument function that's used for "combining" the current element of the list being processed with the accumulated value
The knil parameter is the accumulated output result
To see how this works, imagine for a moment that we have a function such as this:
(define (reverse knil lst)
(if (null? lst)
knil
(reverse (cons (car lst) knil) (cdr lst))))
(reverse '() '(1 2 3 4))
=> '(4 3 2 1)
In the above knil is used to accumulate the result, and it starts in a value of '() because we're building a list as output. And kons is called cons, which builds lists. Let's see another example:
(define (add knil lst)
(if (null? lst)
knil
(add (+ (car lst) knil) (cdr lst))))
(add 0 '(1 2 3 4))
=> 10
In the above knil is used to accumulate the result, and it starts in a value of 0 because we're building a number as output. And kons is called +, which adds numbers.
By now you must have realized that both examples share the same structure of a solution, both consume an input list and the only things that change is how we "combine" the values pulled from the list and the starting accumulated value. If we're smart, we can factor out the parts that change into a higher order procedure, that receives the changing parts as parameters - thus fold1 is born:
(define (fold1 kons knil lst)
(if (null? lst)
knil
(fold1 kons (kons (car lst) knil) (cdr lst))))
And both of the above examples can be easily expressed in terms of fold1, just pass along the right parameters:
(define (reverse lst)
(fold1 cons '() lst))
(define (add lst)
(fold1 + 0 lst))
Now for the second part of the question: if you want to flatten a list with fold1 you can try this:
(define (helper x lst)
(if (pair? x)
(fold1 helper lst x)
(cons x lst)))
(define (flatten lst)
(reverse (helper lst '())))
(flatten '(1 2 (3) (4 (5)) 6))
=> '(1 2 3 4 5 6)
Following code using 'named let' and 'for' loop can be used to flatten the list of elements which themselves may be lists:
(define (myflatten ll)
(define ol '())
(let loop ((ll ll))
(for ((i ll))
(if (list? i)
(loop i)
(set! ol (cons i ol)))))
(reverse ol))
(myflatten '(a () (b e (c)) (((d)))))
Output:
'(a b e c d)
However, it uses 'set!' which is generally not preferred.
The 'for' loop can also be replaced by 'named let' recursion:
(define (myflatten ll)
(define ol '())
(let outer ((ll ll))
(let inner ((il ll))
(cond
[(empty? il)]
[(list? (first il))
(outer (first il))
(inner (rest il))]
[else
(set! ol (cons (first il) ol))
(inner (rest il))])))
(reverse ol))
Even shorter
(define (myflatten lists)
(foldr append empty lists))
(myflatten (list (list 1 2) (list 3 4 5) (list 6 7) (list 8 9 10)))
> (list 1 2 3 4 5 6 7 8 9 10)
I'm new to Scheme (via Racket) and (to a lesser extent) functional programming, and could use some advise on the pros and cons of accumulation via variables vs recursion. For the purposes of this example, I'm trying to calculate a moving average. So, for a list '(1 2 3 4 5), the 3 period moving average would be '(1 2 2 3 4). The idea is that any numbers before the period are not yet part of the calculation, and once we reach the period length in the set, we start averaging the subset of the list according the chosen period.
So, my first attempt looked something like this:
(define (avg lst)
(cond
[(null? lst) '()]
[(/ (apply + lst) (length lst))]))
(define (make-averager period)
(let ([prev '()])
(lambda (i)
(set! prev (cons i prev))
(cond
[(< (length prev) period) i]
[else (avg (take prev period))]))))
(map (make-averager 3) '(1 2 3 4 5))
> '(1 2 2 3 4)
This works. And I like the use of map. It seems composible and open to refactoring. I could see in the future having cousins like:
(map (make-bollinger 5) '(1 2 3 4 5))
(map (make-std-deviation 2) '(1 2 3 4 5))
etc.
But, it's not in the spirit of Scheme (right?) because I'm accumulating with side effects. So I rewrote it to look like this:
(define (moving-average l period)
(let loop ([l l] [acc '()])
(if (null? l)
l
(let* ([acc (cons (car l) acc)]
[next
(cond
[(< (length acc) period) (car acc)]
[else (avg (take acc period))])])
(cons next (loop (cdr l) acc))))))
(moving-average '(1 2 3 4 5) 3)
> '(1 2 2 3 4)
Now, this version is more difficult to grok at first glance. So I have a couple questions:
Is there a more elegant way to express the recursive version using some of the built in iteration constructs of racket (like for/fold)? Is it even tail recursive as written?
Is there any way to write the first version without the use of an accumulator variable?
Is this type of problem part of a larger pattern for which there are accepted best practices, especially in Scheme?
It's a little strange to me that you're starting before the first of the list but stopping sharply at the end of it. That is, you're taking the first element by itself and the first two elements by themselves, but you don't do the same for the last element or the last two elements.
That's somewhat orthogonal to the solution for the problem. I don't think the accumulator is making your life any easier here, and I would write the solution without it:
#lang racket
(require rackunit)
;; given a list of numbers and a period,
;; return a list of the averages of all
;; consecutive sequences of 'period'
;; numbers taken from the list.
(define ((moving-average period) l)
(cond [(< (length l) period) empty]
[else (cons (mean (take l period))
((moving-average period) (rest l)))]))
;; compute the mean of a list of numbers
(define (mean l)
(/ (apply + l) (length l)))
(check-equal? (mean '(4 4 1)) 3)
(check-equal? ((moving-average 3) '(1 3 2 7 6)) '(2 4 5))
Well, as a general rule, you want to separate the manner in which you recurse and/or iterate from the content of the iteration steps. You mention fold in your question, and this points in the right step: you want some form of higher-order function that will handle the list traversal mechanics, and call a function you supply with the values in the window.
I cooked this up in three minutes; it's probably wrong in many ways, but it should give you an idea:
;;;
;;; Traverse a list from left to right and call fn with the "windows"
;;; of the list. fn will be called like this:
;;;
;;; (fn prev cur next accum)
;;;
;;; where cur is the "current" element, prev and next are the
;;; predecessor and successor of cur, and accum either init or the
;;; accumulated result from the preceeding call to fn (like
;;; fold-left).
;;;
;;; The left-edge and right-edge arguments specify the values to use
;;; as the predecessor of the first element of the list and the
;;; successor of the last.
;;;
;;; If the list is empty, returns init.
;;;
(define (windowed-traversal fn left-end right-end init list)
(if (null? list)
init
(windowed-traversal fn
(car list)
right-end
(fn left-end
(car list)
(if (null? (cdr list))
right-end
(second list))
init)
(cdr list))))
(define (moving-average list)
(reverse!
(windowed-traversal (lambda (prev cur next list-accum)
(cons (avg (filter true? (list prev cur next)))
list-accum))
#f
#f
'()
list)))
Alternately, you could define a function that converts a list into n-element windows and then map average over the windows.
(define (partition lst default size)
(define (iter lst len result)
(if (< len 3)
(reverse result)
(iter (rest lst)
(- len 1)
(cons (take lst 3) result))))
(iter (cons default (cons default lst))
(+ (length lst) 2)
empty))
(define (avg lst)
(cond
[(null? lst) 0]
[(/ (apply + lst) (length lst))]))
(map avg (partition (list 1 2 3 4 5) 0 3))
Also notice that the partition function is tail-recursive, so it doesn't eat up stack space -- this is the point of result and the reverse call. I explicitly keep track of the length of the list to avoid either repeatedly calling length (which would lead to O(N^2) runtime) or hacking together a at-least-size-3 function. If you don't care about tail recursion, the following variant of partition should work:
(define (partition lst default size)
(define (iter lst len)
(if (< len 3)
empty
(cons (take lst 3)
(iter (rest lst)
(- len 1)))))
(iter (cons default (cons default lst))
(+ (length lst) 2)))
Final comment - using '() as the default value for an empty list could be dangerous if you don't explicitly check for it. If your numbers are greater than 0, 0 (or -1) would probably work better as a default value - they won't kill whatever code is using the value, but are easy to check for and can't appear as a legitimate average
Before I start: YES, this is homework from college. Before I get told that I'm lazy and evil: this part of the homework was to convert two functions we already had, this one is the 6th.
(define (flatten-list a-list)
(cond ((null? a-list) '())
((list? (car a-list))
(append (flatten-list (car a-list)) (flatten-list (cdr a-list))))
(else (cons (car a-list) (flatten-list (cdr a-list))))))
The function, as you can guess, flattens a list even if it's nested. My specific problem with the transformation comes in the (list? (car a-list)) condition, in which I'm doing two recursive calls. I already did fibonacci, which I can do by just having two "acummulators" on the tail recursion. However, my mind is not trained in this yet to know how it should go.
I would appreciate if I was given hints and not the result. Thanks!
Here's my solution:
(define (flatten-iter a-list)
(define (flat-do acc lst-interm lst)
(cond
((null? lst)
(reverse acc))
((and (list? lst-interm) (not (null? lst-interm)))
(flat-do acc (car lst-interm) (append (cdr lst-interm) lst)))
((not (list? lst-interm))
(flat-do (cons lst-interm acc) empty lst))
((list? (car lst))
(flat-do acc (car lst) (cdr lst)))
(else
(flat-do (cons (car lst) acc) empty (cdr lst)))))
(flat-do empty empty a-list))
(flatten-iter (list 1 (list 2 (list 3 4 (list 5 empty 6))) 7 8))
=> (1 2 3 4 5 6 7 8)
Tail-recrusive functions require that they never return, and thus you can't use stack for storing your program's state. Instead, you use function arguments to pass the state between function calls. Therefore, we need to determine how to maintain the state. Because the result of our function is list?, it's meaningful to grow an empty list; we're using acc for this purpose. You can see how it works in else branch above. But we should be able to process nested lists. And while we're going deeper, we should keep the rest elements of the nested list for further processing. Sample list: (list 1 (list 2 3) 4 5)
Until (list 2 3) we have already added 1 to accumulator. Since we can't use stack, we need some other place to store the rest elements of the list. And this place is the lst argument, which contains elements of the original list to be flattened. We can just append the lst to the rest elements (cdr (list 2 3)) which are (list 3), and proceed with the list's head we stumbled upon while flattening, i. e. (car (list 2 3)) which is just 2. Now, (and (list? lst-interm) (not (null? lst-interm))) succeeds because flat-do is called this way:
(flat-do (list 1) (list 2 3) (list 4 5))
and the condition triggers this code:
(flat-do (list 1) (car (list 2 3)) (append (cdr (list 2 3)) (list 4 5)))
flat-do again is called this way: (flat-do (list 1) 2 (list 3 4 5))
The condition (not (list? 2)) now succeeds and the code (flat-do (cons 2 1) empty (list 3 4 5)) is evaluated.
The rest processing is done with else branch until lst is null? and reverse is performed on acc. Function then returns the reversed accumulator.
How can I pass a list as a parameter to a function adding elements to it recursively,and have it unmodified when it comes out of recursion?
I want to use the list at each level of recursion with the list having the values added by deeper recursion levels.
To be more specific I want to do a DFS search on a graph and I want to store in the list the nodes I visited.
One method of doing this is just to return the list so you have access to it at higher levels of recursion.
Another method is to have your list be stored in a variable outside of the recursion. In other words not stored on the stack. Since it is not a good idea to use a global variable for this we need to have some local recursion.
The following code is a foolish way to reverse a list but it does illustrate the technique I am talking about.
(define (letrecreverse lst)
(letrec ((retlist '())
(reverse (lambda (lst)
(if (null? lst)
'()
(begin
(set! retlist (cons (car lst) retlist))
(reverse (cdr lst)))))))
(reverse lst)
retlist))
(letrecreverse '(1 2 3 4))
;outputs '(4 3 2 1)
Can you adopt this technique for your purposes?
If you build a new list by consing a value onto an old list, that old list is unmodified.
(define old '(1 2 3))
(define new (cons 55 old))
new
>(55 1 2 3)
old
>(1 2 3)
The 'tail' of the first cons in "new" is the list "old". But old hasn't changed.
(cdr new)
> (1 2 3)
If I understood your question correctly, this could be one solution:
;; Just a helper to print the current list.
(define (show list)
(display "list = ")
(display list)
(newline)
(flush-output))
;; Maximum depth of recursion
(define max-recur 5)
;; Original list is backed-up here.
(define orig-list null)
(define (recur list depth)
(if (null? orig-list)
(set! orig-list list))
(cond ((< depth max-recur)
(show list)
(recur (cons (random max-recur) list) (add1 depth)))
(else orig-list)))
Sample run:
> (recur '(1) 0)
list = (1)
list = (1 1)
list = (2 1 1)
list = (3 2 1 1)
list = (4 3 2 1 1)
(1) ;; In the end you get the original list back.