(define depth-count
(lambda (l)
(let ((visited '())
(counter 0))
(let iter ((l l))
(cond ((pair? l)
(if (memq l visited)
(set! counter (+ 1 counter))
(begin
(set! visited (cons l visited))
(iter (car l))
(iter (cdr l)))))
(else '()))) counter)))
Imho, that else branch is unnecessary or just wrong, however that code seems to work, but I am not sure..
When I have .. let's say
(define l0 '(a b c))
(set-car! l0 l0)
(set-car! (cdr l0) l0)
(depth-count l0)
It should return 2, right? Is is correct then?
You are correct that the expression (else '()) is superfluous. It means that your cond expression will sometimes evaluate to the empty list. Hence, your inner let will sometimes evaluate to the empty list.
It is superfluous because you are not using the result of the inner let for anything. The result is discarded by the outer let, which returns the value of its final sub-expression: counter.
Yes, 2 is a reasonable (predictable) result for the input you've suggested.
As for its correctness, you really need to state more clearly what you are trying to achieve. The 'depth' of a 'cyclic list' is not a well-defined concept.
Related
I'm new to Scheme and Lisp in general, and upon learning I've stumbled upon a cryptic syntax used in local procedure binding:
(define mock
(lambda (s)
;; this is what I don't understand
(let splice ([l '()] [m (car s)] [r (cdr s)])
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))))
It took me a while to grasp that splice is a scoped procedure with 3 arities. Rewriting this in an ML-esque style it seems to produce similar output:
(define mock2
(lambda (s)
;; define `splice` first
(define splice
(lambda (la lb lc)
(append
(map (lambda (x) (cons lb x)) lc)
(if (null? lc) '()
(splice (cons lb la) (car lc) (cdr lc))))))
;; bind `splice` and its arguments together and call it with them
(let ([sp splice] [l '()] [m (car s)] [r (cdr s)])
(splice l m r))))
The second version is a bit longer and somewhat look more imperative, but defining splice as a normal procedure inside the scope before binding it in parallel with the arguments (or just chuck them in as-is) and calling it looks saner.
Question is are these two versions replaceable? If yes, could you help explain the first version's syntax of binding local variables (l, m, and r) within the splice binding form?
Calling splice is like re-entering a loop, which is what it is there for. A tail call is a goto anyway. It is often named loop, instead of thinking up some special name for it.
"looks saner" is debatable, and actually with Schemers you'll lose this one, because this is a very popular Scheme construct, called "named let". It is usually re-written with letrec btw, if/when one wants to rewrite it, to understand it better. Internal define can be used as well, but then, why not use (define (mock s) ... in the first place.
So, the usual way to re-write this
(define mock ; or: (define (mock s) ...
(lambda (s)
(let splice ([l '()] [m (car s)] [r (cdr s)])
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))))
is this:
(define mock
(lambda (s)
(letrec ([splice (lambda (l m r) ; or: (define (splice l m r) ...
(append
(map (lambda (x) (cons m x)) r)
(if (null? r) '()
(splice (cons m l) (car r) (cdr r)))))])
(splice '() (car s) (cdr s)))))
and writing it in the named let way saves one from having it defined in one place and called in another, potentially far away. A call enters its body from the start anyway, and named let better reflects that.
This is pretty self-explanatory. The transformation from one form to the other is purely syntactical, and both can be used interchangeably.
After figuring out the recursive version of this algorithm, I'm attempting to create an iterative (tail-recursive) version.
I'm quite close, but the list that is returned ends up being reversed.
Here is what I have so far:
(define (first-n-iter lst n)
(define (iter lst lst-proc x)
(cond
((= x 0) lst-proc)
(else (iter (cdr lst) (cons (car lst) lst-proc) (- x 1)))))
(if (= n 0)
'()
(iter lst '() n)))
i.e. Calling (first-n-iter '(a b c) 3) will return (c b a).
Could someone suggest a fix? Once again, I'd like to retain the tail-recursion.
note: I'd prefer you not suggest just calling (reverse lst) on the returned list..
You can do the head sentinel trick to implement a tail recursive modulo cons
(define (first-n-iter lst n)
(define result (cons 'head '()))
(define (iter tail L-ns x)
(cond
((= x 0) (cdr result))
((null? L-ns)
(error "FIRST-N-ITER input list " lst " less than N" n))
(else
(begin (set-cdr! tail (list (car L-ns)))
(iter (cdr tail) (cdr L-ns) (- x 1))))))
(iter result lst n))
(first-n-iter '(a b c d e f g h i j k l m n o p q r s t u v w x y z) 8))
;Value 7: (a b c d e f g h)
Also added a cond clause to catch the case where you try to take more elements than are actually present in the list.
You could flip the arguments for your cons statement, list the last (previously first) arg, and change the cons to append
(define (first-n-iter lst n)
(define (iter lst acc x)
(cond
[(zero? x) acc]
[else (iter (cdr lst) (append acc (list (car lst))) (sub1 x))]))
(iter lst empty n))
which will work as you wanted. And if you're doing this as a learning exercise, then I think that's all you need. But if you're actually trying to make this function, you should know that it's been done already-- (take lst 3)
Also, you don't need your if statement at all-- your check for (= x 0) would return '() right away, and you pass in (iter lst '() n) as it is. So the (if (= n 0) ... ) is doing work that (cond [(= x 0)...)' would already do for you.
I was assigned to write a merge sort in Scheme but I have some issues with it. I showed it my professor and he said there is one simple mistake. Can someone help me?
Plzz!
(define msort
(lamdba(1st)
(cond
((null?? 1st) 1st)
((null? (cdr 1st)) 1st)
(#t ((letrec ((half (quotient (lenght 1st) 2))
(merge (lamdba (a b result)
(cond ((null? a) (apped (reserve a) result))
((null? b) (append (reserve a) result))
((> (car a) (car b) (merge a (cdr b) (cons (car b) result))
(#t (merge (cdr a) b (cons (car a) result)))))))
(merge (msort (take 1st half)) (msort (drop 1st half)) '()))))))
One simple mistake? He probably referred to #1, but even after fixing that you have some identifiers and parenthesis to fix:
lambda, null?, length, append, and reverse is spelled incorrectly.
letrec result gets applied since you have excess parenthesis around it.
cond in merge where you compare elements are missing parenthesis two places.
It's obvious you need help with parenthesis matching so you should download a decent IDE to write code in. I use DrRacket for Scheme development (#!R5RS, #!R6RS and #!racket) and it idents (just press CTRL+i to get it reidented after pasting in code) and indicate where function names are written wrong when you hit RUN.
Making merge a global function in the beginning and perhaps move it to a letrec later (if you have to) might ease development. Eg. you could find errors by testing stuff like (merge '(3 2 1) '()).
This is no guarantee the program will work since I only address syntax here. You need to debug it! DrRacket has a debugger too!
I think it is useful to implement first a function that allow to merge two ordered lists:
(define (merge l1 l2)
(if (empty? l1)
l2
(if (empty? l2)
l1
(if (< (car l1) (car l2))
(cons (car l1) (merge (cdr l1) l2))
(cons (car l2) (merge l1 (cdr l2)))))))
Now assume we have a function (get ls pos) capable to return the element of ls in position pos:
(define (get ls pos)
(if (= pos 1)
(car ls)
(get (cdr ls) (- pos 1))))
Finally, we can implement mergesort function:
(define (mergesort l p r)
(if (= p r)
(cons (get l p) empty)
(merge (mergesort l p (floor (/ (+ p r) 2))) (mergesort l (+ (floor (/ (+ p r) 2)) 1) r))))
On page 66 of "The Seasoned Schemer" it says that (let ...) is an abbreviation for :
(let ((x1 a1) ... (xn an)) b ...) = ((lambda (x1 ... xn) b ...) a1 ... an)
Its used on for example on page 70:
(define depth*
(lambda (l)
(let ((a (add1 (depth* (car l))))
(d (depth* (cdr l))))
(cond
((null? l) 1)
((atom? (car l)) d)
(else (cond
((> d a) d)
(else a)))))))
But that above definition of lambda would suggest that (add1 (depth* (car l)) and (depth* (cdr l)) are evaluated and passed into the lambda represented by (lambda (x1 ... xn) b ...). But this would mean that the list l, which could potentially be empty, would be passed to car and cdr before the null check in (null? l) 1) is ever done.
You're right in stating that (car l) and (cdr l) will get executed before testing if l is null, therefore raising an error if l is indeed null. Keep reading the book, in the following two pages this is explained, and a correct version of depth* is shown.
The let syntactic keyword accepts the following form (ignore 'named-let'):
(define-syntax let
(syntax-rules ()
((let ((identifier expression) ...) body ...)
;; ...)))
At the point where let is used each of expression ... is evaluated. The expressions are evaluated in an unspecified order.
In your case, the expressions for a and d involving depth* will be evaluated before the body. Thus, as you've concluded, l could be '() when car and cdr are invoked.
I have been working alongside The Little Schemer to learn Scheme and using PLT-Scheme for my environment.
The Little Schemer has helped me tremendously with recursion (it is straightforward for me now) but I'm stuck on a portion of the book that introduces "collectors" and calls the function as a whole a continuation.
Here is the example code they have used. I understand the recursive elements but I am stuck, in particular on the lambda functions - my mind can't follow the path and how the arguments for that lambda function are set (since their only call is to call them again in recursion, there is no concrete use within the function body).
If someone could more-or-less give me a break down of the path of computation through the recursion of the function into the lambda collectors, that may help me.
;; Build a nested list of even numbers by removing the odd ones from its
;; argument and simultaneously multiply the even numbers and sum the odd
;; numbers that occur in its argument.
(define (even-only-collector l col)
(cond
((null? l)
(col (quote ()) 1 0))
((atom? (car l))
(cond
((even? (car l))
(even-only-collector (cdr l)
(lambda (newl p s)
(col (cons (car l) newl)
(* (car l) p) s))))
(else
(even-only-collector (cdr l)
(lambda (newl p s)
(col newl
p (+ (car l) s)))))))
(else
(even-only-collector (car l)
(lambda (al ap as)
(even-only-collector (cdr l)
(lambda (dl dp ds)
(col (cons al dl)
(* ap dp)
(+ as ds)))))))))
;; The collector function
(define (collector newl product sum)
(cons sum
(cons product newl)))
Thank you in advance!!
Try something simpler to see how this works. For example, here's a version of a list-sum function that receives a continuation argument (which is often called k):
(define (list-sum l k)
(if (null? l)
???
(list-sum (cdr l) ???)))
The basic pattern is there, and the missing parts are where the interesting things happen. The continuation argument is a function that expects to receive the result -- so if the list is null, it's clear that we should send it 0, since that is the sum:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) ???)))
Now, when the list is not null, we call the function recursively with the list's tail (in other words, this is an iteration), but the question is what should the continuation be. Doing this:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) k)))
is clearly wrong -- it means that k will eventually receive the the sum of (cdr l) instead of all of l. Instead, use a new function there, which will sum up the first element of l too along with the value that it receives:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (sum) (+ (car l) sum)))))
This is getting closer, but still wrong. But it's a good point to think about how things are working -- we're calling list-sum with a continuation that will itself receive the overall sum, and add the first item we see now to it. The missing part is evident in the fact that we're ignoring k. What we need is to compose k with this function -- so we do the same sum operation, then send the result to k:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (compose k (lambda (s) (+ s (car l)))))))
which is finally working. (BTW, remember that each of these lambda functions has its own "copy" of l.) You can try this with:
(list-sum '(1 2 3 4) (lambda (x) x))
And finally note that this is the same as:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (s) (k (+ s (car l)))))))
if you make the composition explicit.
(You can also use this code in the intermediate+lambda student language, and click the stepper button to see how the evaluation proceeds -- this will take a while to go over, but you'll see how the continuation functions get nested, each with it's own view of the list.)
Here's one way to help you "get a more concrete idea". Imagine if the collector were defined thus:
(define (collector l p s)
(display l)
(newline)
(display p)
(newline)
(display s)
(newline))
You can see in the base case, if you pass in an empty list, it will call your function with arguments '(), 1, and 0. Now, work with a one-element list, and see what it'll call your function with. Keep working up with longer and longer lists, until you figure out what's going on.
Good luck!