So i'm reading the SCIP book which uses the Lisp language to explain the core concepts and i'm currently stuck on Linear recursive vs Linear iterative process difference.
and the example used to demonstrate the difference is the computing of n!
Linear recursive process
(if (= n 1)
1
(* n (factorial (- n 1)))))
it produces this process :
(* 6 (factorial 5))
(* 6 ( * 5 (factorial 4)))
(* 6 ( * 5 ( * 4 ( factorial 3))))
(* 6 ( * 5 ( * 4 ( * 3 ( factorial 2)))))
(* 6 ( * 5 ( * 4 ( * 3 (*2 (factorial1))))))
(* 6 ( * 5 ( * 4 ( * 3 (*2 1)))))
(* 6 ( * 5 ( * 4 ( * 3 2))))
(* 6 ( * 5 ( * 4 6)))
(* 6 ( * 5 24))
(* 6 120)
720
Linear iterative process
(define (factorial n)
(if (= n 1)
1
(* n (factorial (- n 1)))))
produces the following process
(Factorial 6)
(Fact-tier 1 1 6)
(Fact-tier 1 2 6)
(Fact-tier 2 3 6)
(Fact-tier 6 4 6)
(Fact-tier 24 5 6)
(Fact-tier 120 5 6)
(Fact-tier 720 6 6)
720
Even though i did understand the main difference between them i still don't get this paragraph
"The contrast between the two processes can be seen in another way. In the iterative case, the program
variables provide a complete description of the state of the process at any point. If we stopped the
computation between steps, all we would need to do to resume the computation is to supply the interpreter
with the values of the three program variables. Not so with the recursive process. In this case there is some
additional "hidden" information, maintained by the interpreter and not contained in the program variables,
which indicates ``where the process is'' in negotiating the chain of deferred operations. The longer the
chain, the more information must be maintained.
The recursive version has the following trace:
0: (FACTORIAL 10)
1: (FACTORIAL 9)
2: (FACTORIAL 8)
3: (FACTORIAL 7)
4: (FACTORIAL 6)
5: (FACTORIAL 5)
6: (FACTORIAL 4)
7: (FACTORIAL 3)
8: (FACTORIAL 2)
9: (FACTORIAL 1)
9: FACTORIAL returned 1
8: FACTORIAL returned 2
7: FACTORIAL returned 6
6: FACTORIAL returned 24
5: FACTORIAL returned 120
4: FACTORIAL returned 720
3: FACTORIAL returned 5040
2: FACTORIAL returned 40320
1: FACTORIAL returned 362880
0: FACTORIAL returned 3628800
Intermediate results for recursive calls are used to produce new results. There need to be some memory to store intermediate results while the recursive calls are made, in order to combine them and compute the result when they finish. This storage is on the call stack, in stack frames.
The "iterative" process has the following trace:
0: (FACTORIAL 1 1 10)
1: (FACTORIAL 1 2 10)
2: (FACTORIAL 2 3 10)
3: (FACTORIAL 6 4 10)
4: (FACTORIAL 24 5 10)
5: (FACTORIAL 120 6 10)
6: (FACTORIAL 720 7 10)
7: (FACTORIAL 5040 8 10)
8: (FACTORIAL 40320 9 10)
9: (FACTORIAL 362880 10 10)
10: (FACTORIAL 3628800 11 10)
10: FACTORIAL returned 3628800
9: FACTORIAL returned 3628800
8: FACTORIAL returned 3628800
7: FACTORIAL returned 3628800
6: FACTORIAL returned 3628800
5: FACTORIAL returned 3628800
4: FACTORIAL returned 3628800
3: FACTORIAL returned 3628800
2: FACTORIAL returned 3628800
1: FACTORIAL returned 3628800
0: FACTORIAL returned 3628800
In the case of the iterative process, you can see that the result is always the same: intermediate results are just passed back unchanged to the toplevel. In other words, we already know the final result when we are at the innermost call. No storage is necessary for any intermediate value, since everything is kept in the function arguments. You could just as well mutate the arguments with the new values and loop.
In fact, this is basically what happens when calls in tail-position are optimized: recursive calls reuse the same stack frame as their caller, flattening the trace as follows:
(FACTORIAL 1 1 10)
(FACTORIAL 1 2 10)
(FACTORIAL 2 3 10)
(FACTORIAL 6 4 10)
(FACTORIAL 24 5 10)
(FACTORIAL 120 6 10)
(FACTORIAL 720 7 10)
(FACTORIAL 5040 8 10)
(FACTORIAL 40320 9 10)
(FACTORIAL 362880 10 10)
(FACTORIAL 3628800 11 10)
FACTORIAL returned 3628800
You end up having the same behaviour as if you had use a loop construct. But note that even with loops, you can benefit from this trick: tail-call elimination is not limited to recursive calls, it may be done whenever you can safely reuse a frame when calling a function.
Related
I like writing code to the same thing that built-in functions do. It is always a great exercise for me.
In racket there is a bult-in function called "member" which checks if a certain element is inside a list. If true, the function returns the rest/cdr o the list If false, the function returns #f. Examples:
> (member 2 (list 1 2 3 4))
'(2 3 4)
> (member 9 (list 1 2 3 4))
#f
I did the following code:
(require racket/trace)
(define (member-mine lista num)
(cond ((equal? (car lista) num) (cdr lista))
((equal? (car lista) '()) #f)
(else (member-mine (cdr lista) num))))
(define small-list (list 1 2 3 4 5 6 7 8))
(trace member-mine)
And, when I try using it with the cool tool trace, I am partially successful.
Calling:
(member-mine small-list 1)
Returns:
>(member-mine '(1 2 3 4 5 6 7 8) 1)
<'(2 3 4 5 6 7 8)
Calling:
(member-mine small-list 8)
Returns:
>(member-mine '(1 2 3 4 5 6 7 8) 8)
>(member-mine '(2 3 4 5 6 7 8) 8)
>(member-mine '(3 4 5 6 7 8) 8)
>(member-mine '(4 5 6 7 8) 8)
>(member-mine '(5 6 7 8) 8)
>(member-mine '(6 7 8) 8)
>(member-mine '(7 8) 8)
>(member-mine '(8) 8)
<'()
The problem is when I call an element which is not in the list given. The output should be #f:
(member-mine small-list 9)
Which returns is an error:
>(member-mine '(1 2 3 4 5 6 7 8) 9)
>(member-mine '(2 3 4 5 6 7 8) 9)
>(member-mine '(3 4 5 6 7 8) 9)
>(member-mine '(4 5 6 7 8) 9)
>(member-mine '(5 6 7 8) 9)
>(member-mine '(6 7 8) 9)
>(member-mine '(7 8) 9)
>(member-mine '(8) 9)
>(member-mine '() 9)
. . car: contract violation
expected: pair?
given: '()
How do I manage to deal with the empty?
There are some issues with your code. As a first observation you have switched the contract so that the list comes first instead of last.
It also seem that you are checking if one of the elements is the empty list and not the list itself. Thus your member would terminate with #f in this case:
(member-mine '(() 1 2 3 4 5 6 7 8) 1) ; ==> #f
So your member should check if the whole argument is null? (empty?) or perhaps check if it's not pair?. Then it should evaluate to #f.
If the first element matches your search, then the original member evaluates to the whole argument with the match as the first element and not the cdr like in your code.
Move the empty case to be the first branch of the conditional. When the empty list is passed into your function on the final recursive call, you request the car of the list, which cannot be done because the list is empty. Putting the empty case fist should cause the function to terminate with #f before reaching a call to car.
Another way to check empty list is to check its length:
(define (member-mine lista num)
(cond
((equal? (length lista) 0) #f) ; '=' can also be used instead of 'equal?'
((equal? (car lista) num) (cdr lista))
(else (member-mine (cdr lista) num))))
(define small-list (list 1 2 3 4 5 6 7 8))
(member-mine small-list 9)
Output:
#f
But proper way is:
(empty? lista) or (null? lista)
http://www.4clojure.com/problem/23: "Write a function which reverses a sequence"
One solution is (fn [x] (reduce conj () x)), which passes all the tests. However, I'm curious why that solution works for the first test:
(= (__ [1 2 3 4 5]) [5 4 3 2 1])
Inlining the function evaluates to true in the REPL:
(= ((fn [x] (reduce conj () x)) [1 2 3 4 5]) [5 4 3 2 1])
true
However, if I evaluate the first argument to the =, I get (5 4 3 2 1), and (= (5 4 3 2 1) [5 4 3 2 1]) throws a ClassCastException.
Why does the former work while the latter doesn't? It seems like they should be equivalent …
The problem is that your list literal (5 4 3 2 1) is being evaluated as a function call. To use it properly you need to quote it, like so:
(= '(5 4 3 2 1) [5 4 3 2 1]) ;; => true
another way to do it without reduce is to use into ()
as it works exatcly as your reduction. So when you fill the blank this way, it solves the task:
(= (into () [1 2 3 4 5]) [5 4 3 2 1]) ;; true
(= (into () (sorted-set 5 7 2 7)) '(7 5 2)) ;; true
(= (into () [[1 2][3 4][5 6]]) [[5 6][3 4][1 2]]) ;; true
In the Hyperspec they have this example for maplist:
(maplist #'append '(1 2 3 4) '(1 2) '(1 2 3))
=> ((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3))
which I don't quite grasp. Following the apparent logic, I would have guessed
=>((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3) (3 4 3) (4))
It seems that because we've "exhausted" the middle list after producing the two sublists, it's game over. Why? What am I missing?
Your assertion that it stops after the middle list is "exhausted" seems to be correct; from the documentation:
maplist is like mapcar except that function is applied to successive sublists of the lists. function is first applied to the lists themselves, and then to the cdr of each list, and then to the cdr of the cdr of each list, and so on.
So it makes sense that it would stop after hitting the end of the shortest list, because there would be no more values to use from that list and it seems to try to use all the (sub)lists each time 'round.
EDIT
As Samuel Edwin Ward pointed out:
The part describing mapcar includes "The iteration terminates when the shortest list runs out, and excess elements in other lists are ignored."
Just a quick REPL experiment:
[1]> (maplist #'append '(1 2 3 4) '(1 2) '(1 2 3))
((1 2 3 4 1 2 1 2 3) (2 3 4 2 2 3))
[2]> (maplist #'append '(1 2 3 4) '(1 2 3) '(1 2))
((1 2 3 4 1 2 3 1 2) (2 3 4 2 3 2))
[3]> (maplist #'append '(1 2 3 4) '(1 2 3) '(1 2 5))
((1 2 3 4 1 2 3 1 2 5) (2 3 4 2 3 2 5) (3 4 3 5))
I'm trying to use "map" and "accumulating" functions in scheme for sorting unknown amount of listing into a lists that the first will have all the first places of the olds lists and so on.
(1 2 3.. ) (4 5 6..) (7 8 9..)...
to this list:
(1 4 7) (2 5 8) (3 6 9).
I was writing this:
(accumulate (lambda (x y) (if (null? y) x (map cons x y))) null '((1 2 3) (4 5 6) (7 8 9) (9 10 11) (12 13 14)))
and it keeps giving me the annoying dot in the end...
((1 4 7 9 . 12) (2 5 8 10 . 13) (3 6 9 11 . 14)).
what seemes to be the problem? thanks!
Try this:
(if (null? y)
(map list x)
(map cons x y))
(define (accumulate x . rest)
(append (list x) rest))
> (map accumulate '(1 2 3) '(4 5 6) '(7 8 9))
=> ((1 4 7) (2 5 8) (3 6 9))
> (map accumulate '(1 2 3 4) '(5 6 7 8) '(9 10 11 12) '(13 14 15 16))
=> ((1 5 9 13) (2 6 10 14) (3 7 11 15) (4 8 12 16))
What is the "correct" construct in Common Lisp to apply elementwise operations to multidimensional arrays?
The following examples should help illustrate what I'm trying to do:
A) Suppose I want to increase every element of an array by one:
0 1 2 1 2 3
3 4 5 -> 4 5 6
6 7 8 7 8 9
B) Suppose I want to add 2 arrays:
1 2 -1 -1 0 1
3 4 + -2 -2 -> 1 2
5 6 -3 -3 2 3
C) Suppose I want to find the largest elements of several arrays, elementwise:
max( 0 1 , 4 -1 , 0 0 ) -> 4 1
2 3 0 0 8 1 8 3
Basically I think I'm looking for some sort of "arraymap" function which would be used in like so: (arraymap f A1 A2 ... An), where f takes n arguments as input, and the Ai are arrays of the same size.
In the above examples it would be used like so:
A)
(setq M #2A((0 1 2) (3 4 5) (6 7 8)))
(arraymap #'incf M)
B)
(setq M #2A((1 2) (3 4) (5 6)))
(setq N #2A((-1 -1) (-2 -2) (-3 -3)))
(arraymap #'+ M N)
C)
(setq M #2A((0 1) (2 3)))
(setq N #2A((4 -1) (0 0)))
(setq O #2A((0 0) (8 1)))
(arraymap #'max M N O)
I have tried some constructs with map and loop, but it seems to not work since multidimensional arrays are not a sequence type.
There are four ways to do that:
Write an ARRAY-MAP function based on the array dimensions and iterate over those.
Use ROW-MAJOR-AREF, which views the array like a vector.
Use displaced one-dimensional arrays for the operations.
Example for a use of displaced arrays:
(defun array-map (function &rest arrays)
"maps the function over the arrays.
Assumes that all arrays are of the same dimensions.
Returns a new result array of the same dimension."
(flet ((make-displaced-array (array)
(make-array (reduce #'* (array-dimensions array))
:displaced-to array)))
(let* ((displaced-arrays (mapcar #'make-displaced-array arrays))
(result-array (make-array (array-dimensions (first arrays))))
(displaced-result-array (make-displaced-array result-array)))
(declare (dynamic-extent displaced-arrays displaced-result-array))
(apply #'map-into displaced-result-array function displaced-arrays)
result-array)))
Using it:
CL-USER 3 > (array-map #'1+ #2A((0 1 2) (3 4 5) (6 7 8)))
#2A((1 2 3) (4 5 6) (7 8 9))
CL-USER 4 > (array-map #'+ #2A((1 2) (3 4) (5 6)) #2A((-1 -1) (-2 -2) (-3 -3)) )
#2A((0 1) (1 2) (2 3))
Use internal, implementation specific, operations for efficient array operations.
For anyone coming here looking for an up-to-date answer to this question: https://github.com/bendudson/array-operations defines aops:each (and aops:each*) that does exactly what the OP asks for.