Can someone explain me what's happening with the two lambda statements in the following code?
(define (remove x ls)
(if (null? ls)
'()
(let ((h (car ls)))
((if (eqv? x h)
(lambda (y) y)
(lambda (y) (cons h y)))
(remove x (cdr ls))))))
What is the 'y' in the above code?
Depending on the if's condition, we're returning one or the other lambda and then immediately applying it (notice the double opening parentheses to the left of the if). The first lambda returns the result of calling the recursion, the second lambda conses an element to the result of calling the recursion, either way the recursion gets called. The y is just the parameter name for the lambdas, which gets bound to the value of (remove x (cdr ls)). The whole thing is equivalent to this, and in fact it should be written like this, not in its current, overly complicated form:
(define (remove x ls)
(if (null? ls)
'()
(let ((h (car ls)))
(if (eqv? x h) ; using `equal?` would be a better idea
(remove x (cdr ls))
(cons h (remove x (cdr ls)))))))
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.
So this function is supposed to swap out x, which is also the key for the hash table, with the value of that key from the hash table, but when the list somehow becomes < void >. Why?
(define (var-helper L)
(for-each (lambda (x) (when (hash-has-key? *variables* x)
(swap x (hash-ref *variables* x) L)))
L))
Here's the swap function I'm using:
(define (swap x y L)
(cond ((empty? L) '())
((list? (car L))
(cons (swap x y (car L))
(swap x y (cdr L))))
((eq? x (car L))
(cons y (swap x y (cdr L))))
((cons (car L) (swap x y (cdr L))))))
Try this:
(define (var-helper L)
(map (lambda (x) (swap x (hash-ref *variables* x) L))
(filter (lambda (x) (hash-has-key? *variables* x))
L)))
As mentioned in the comments, for-each doesn't build a new list as result, it just processes each element, returning an undefined value (<void> in this case). That's why you should use map to return a new list as output.
Also, notice that you must handle the case when one of the elements isn't present in the hash table - for instance, filtering them out first. And one last thing - there's something wrong with the swap function, the last condition is missing the else part.
(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.
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.
EDIT: Thanks to everyone. I'm new to the language(just started using it two days ago), so that's why I'm unfamiliar with conds. I may rewrite it if I have time, but I just wanted to make sure I had the basic logic right. Thanks again!
My assignment is to make a tail-recursive function that removes the nth element from the list, 1 <= n <= listlength, with only two parameters, list x and element n. So, (remove 1 '(a b c d)) will return (b c d). I have written the following, and would like some reassurance that it is indeed tail recursive. The only thing I'm fuzzy on is if the recursive call can be nested inside an IF statement.
(define (remove n x)
; if n is 1, just return the cdr
(if (and (not (list? (car x))) (= n 1))
(cdr x)
; if the car is not a list, make it one, and call recursively
(if (not (list? (car x)))
(remove (- n 1) (cons (list (car x)) (cdr x)))
; if n !=1, insert the cadr into the list at the car.
; Else, append the list at the car with the cddr
(if (not(= n 1))
(remove (- n 1) (cons (append (car x) (list(cadr x))) (cddr x)))
(append (car x) (cddr x))))))
Yes, the procedure is tail-recursive, meaning: wherever a recursive call is performed, it's the last thing that happens in that particular branch of execution, with nothing more to do after the recursion returns - hence, we say that the recursive call is in tail position.
This can be clearly seen if we rewrite the procedure using cond instead of nested ifs, here you'll see that every branch of execution leads to either a base case or a recursive case, and all recursive calls are in tail position:
(define (remove n x)
; base case #1
(cond ((and (not (list? (car x))) (= n 1))
; return from base case, it's not recursive
(cdr x))
; recursive case #1
((not (list? (car x)))
; recursive call is in tail position
(remove (- n 1) (cons (list (car x)) (cdr x))))
; recursive case #2
((not (= n 1))
; recursive call is in tail position
(remove (- n 1) (cons (append (car x) (list(cadr x))) (cddr x))))
; base case #2
(else
; return from base case, it's not recursive
(append (car x) (cddr x)))))
For a more technical explanation of why the consequent/alternative parts of an if special form can be considered tail-recursive, take a look at section 3.5 of the current draft of the Revised^7 Report on the Algorithmic Language Scheme - the language specification, here's a link to the pdf file (in essence the same considerations apply to R5RS, it's just that they're explained in more detail in R7RS). In particular:
If one of the following expressions is in a tail context, then the subexpressions shown as ⟨tail expression⟩ are in a tail context
...
(if ⟨expression⟩ ⟨tail expression⟩ ⟨tail expression⟩)
(if ⟨expression⟩ ⟨tail expression⟩)
Here is the Scheme specification on the tail recursion position for syntactic forms: