Issue unbound variable in chez scheme - scheme

I am defining a function replaceOccurrence that replaces the first occurrence of either of two symbols. I don't understand why list variable is not bound
Chez Scheme Version 9.5
(define replaceOcurrence
(λ (new ocurrence1 ocurrence2 lista)
(cond
((null? lista) '())
(else (cond
((eq? ocurrence1 (car lista))
(cons new (cdr (lista))))
((eq? ocurrence2 (car lista))
(cons new (cdr (lista))))
(else (cons (car lista)
(replaceOcurrence new ocurrence1 ocurrence2 (cdr lista)))))))))
Exception: variable lista is not bound

Chez Scheme does not support λ as a replacement for lambda. Racket does, and says so explicitly in the documentation. Guile appears to support λ too, but I don't see that documented. Since λ is not recognized as a special form in Chez Scheme, the arguments to λ are evaluated first, and since they have not yet been bound, the reported error is issued.
There is another problem in the OP code: lista is alone in parentheses twice; this attempts to call lista as a procedure each time. Also, occurrence is spelled with two Cs; and prefer kebab-case to camelCase in Scheme. Here is the fixed code:
(define replace-occurrence
(lambda (new occurrence1 occurrence2 lista)
(cond
((null? lista) '())
(else
(cond
((eq? occurrence1 (car lista))
(cons new (cdr lista)))
((eq? occurrence2 (car lista))
(cons new (cdr lista)))
(else
(cons (car lista)
(replace-occurrence new occurrence1 occurrence2 (cdr lista)))))))))
The best, and most portable, way to solve OP problem is to simply use lambda. But, if one really wants to use λ, a macro can be used to provide the necessary syntax:
(define-syntax λ
(syntax-rules ()
[(_ formals . body)
(lambda formals . body)]))
With the inclusion of the above macro (and the other necessary changes mentioned in the first part of the answer), OP code can use λ in place of lambda.

Related

Inserting word beside another word starting from the end of list

I have code which is inserting new word on the right side of choosen word
(define insertR
(lambda (new old lst)
(cond
((null? lst) (lst))
(else (cond
((eq? (car lst) old)
(cons old
(cons new (cdr lst))))
(else (cons (car lst)
(insertR new old
(cdr lst)))))))))
i need to make it insert that word beside first appearance of word starting from the end of list. Tried to work with reverse but could not get that to work.
There are two strategies you can take to add it next to the last occurence.
The first is to use a helper and start off with the reverse list. This is very simple and my preferred solution.
(define (insert-by-last-match insert find lst)
(let loop ((lst (reverse lst)) (acc '()))
(if (null? lst)
acc
(let ((a (car lst)))
(if (equal? a find)
(append (reverse (cdr lst))
(list* find insert acc))
(loop (cdr lst) (cons a acc)))))))
The other one is kind of obscure. Whenever you find the element you replace last-match with a callback that replaces the computation since it was made and until it gets called with the replacement and the rest of the list, which of course is the correct result. The work done until the end of the list is simply discarded since it is not used, but we do it since we are not sure if we are going to find a later one and then all the work uptil that is of course included in the result.
(define (insert-by-last-match insert find lst)
(define (helper lst last-match)
(if (null? lst)
(last-match)
(let* ((a (car lst)) (d (cdr lst)))
(cons a
(if (equal? a find)
(let/cc k
(helper d (lambda () (k (cons insert d)))))
(helper d last-match))))))
(helper lst (lambda () lst)))
call/cc (or its variant let/cc) is often described as time travel or advanced goto. It is not very intuitive. Here is a CPS version:
(define (insert-by-last-match insert find lst)
(define (helper lst last-match k)
(if (null? lst)
(last-match)
(let* ((a (car lst)) (d (cdr lst)) (k2 (lambda (v) (k (cons a v)))))
(if (equal? a find)
(helper d (lambda () (k2 (cons insert d))) k2)
(helper d last-match k2)))))
(helper lst (lambda () lst) (lambda (v) v)))
Basically this is the same as the previous only that here I have written the CPS code and with the let/cc version the implementation does it for me and I get to use k exactly where I need it. In this version you see there is no magic or time travel but the execution that should happen later is simply replaced at a point.
Write in a similar way insertL and apply it to the reversed list.
And reverse the result. Then you will have an insertion beside first appearance of word starting from the end of list
(define insertL
(lambda (new old lst)
(cond ((null? lst) '())
((eq? (car lst) old) (cons new lst))
(else (cons (car lst) (insertL new old (cdr lst)))))))
(define last-insertR
(lambda (new old lst)
(let* ((rlst (reverse lst))
(result (insertL new old rlst)))
(reverse result))))
test:
(last-insertR 'aa 'a '(b c d a h i a g))
;; '(b c d a h i a aa g)
By the way, the beauty of cond is that you can put the conditions always at the beginning - listed one under the other.
So one can write your insertR nicer as:
(define insertR
(lambda (new old lst)
(cond ((null? lst) '())
((eq? (car lst) old) (cons old (cons new (cdr lst))))
(else (cons (car lst) (insertR new old (cdr lst)))))))

Scheme if-statement

I'm currently studying Scheme with The Little Schemer and ran into an odd trouble.
Here is my code:
(define rember
(lambda (a lat)
((if (null? lat)
'()
(cond
((eq? a (car lat)) (cdr lat))
(else (rember a (cdr lat))))))))
(rember 'aaa '(bbb aaa))
I used an "if" instead of "cond" in the textbook. When returning from the tail-recursion, it shows this error:
application: not a procedure;
expected a procedure that can be applied to arguments
given: '()
arguments...: [none]
I guess this is because it treats '() in the if-statement as a function and the return value of the tail-recursion as its argument. But since the book doesn't give me so many details about the language, could you explain this a bit for me? (e.g. Is this in fact some kind of language feature? Is there any way that I can stick to "if" in this piece of code? And when can I use "if" safely?)
Thanks.
You have an extra set of parentheses around your if. This
((if (null? lat)
'()
(cond
((eq? a (car lat)) (cdr lat))
(else (rember a (cdr lat))))))
should be this:
(if (null? lat)
'()
(cond
((eq? a (car lat)) (cdr lat))
(else (rember a (cdr lat)))))
Those extra parentheses tell Scheme that you want to call the result of the if like a function, so you get the error saying that '() isn't a function.

Manipulating the Scheme evaluator

I'm trying to manipulate the Scheme evaluator and write a make-unbound! procedure that unbinds a variable from the environment:
(define (make-unbound! var env)
(let ((frame (first-frame env)))
(define (scan vars vals)
(let ((new-frame
(make-frame
(zip
(filter (lambda (x) (not (eq? x (car vars)))) vars)
(filter (lambda (x) (not (eq? x (car vals)))) vals))
env)))
(cond ((null? vars)
(display '(No frame to unbind)))
((eq? var (car vars))
(set-car! vars new-frame)) ; the problem seems to be here
(else (scan (cdr vars) (cdr vals))))))
(scan (frame-variables frame)
(frame-values frame))))
The problem seems to be with where I'm setting the car of the variable. But I'm not sure what it should be changing to....
This looks like exercise 4.13 of SICP. The make-unbound! special form can be evaluated like this using Racket:
(define (remove-association! key lst)
(define (loop prev l)
(cond ((null? l) lst)
((equal? (mcar (mcar l)) key)
(set-mcdr! prev (mcdr l))
lst)
(else (loop l (mcdr l)))))
(cond ((null? lst) '())
((eq? (mcar (mcar lst)) key) (mcdr lst))
(else (loop lst (mcdr lst)))))
(define (unbind-variable! var env)
(define (env-loop env)
(define (scan bindings)
(cond ((massq var bindings)
(set-mcar! env (remove-association! var bindings)))
(else (env-loop (enclosing-environment env)))))
(unless (eq? env the-empty-environment)
(scan (first-frame env))))
(env-loop env))
(define (unbound-variable exp)
(cadr exp))
(define (eval-make-unbound! exp env)
(unbind-variable! (unbound-variable exp)
env))
It removes the first binding that finds with the given symbol, be it in the current frame or any of its enclosing environments. If the symbol was unbound in the first place, it does nothing. I chose to implement the unbind operation in this fashion so that the (possible) bindings in enclosing environments are kept intact.
Don't forget to specify in the eval procedure that the special form make-unbound! is to be evaluated using the eval-make-unbound procedure.
Also, be warned that I made my implementation using Racket's mutable pairs library, so the procedure names I'm using sometimes have an extra m somewhere in their names, meaning: they're defined for mutable pairs. For example: mcar, mcdr, set-mcar!, set-mcdr!, massq. If any of the previous procedures is not found, simply remove the m from the name and try again.

Detecting the caller of a function in Scheme or Racket

In Scheme or Racket is it possible to detect the caller of a function?
For example, I can write a function to test if a list is a list of atoms as follows:
(define atom? (lambda (x) (and (not (pair? x)) (not (empty? x)))))
(define lat? (lambda (l)
(define latt?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (latt? (cdr l)))
(else #f))))
(if (null? l) #f (latt? l))))
but instead of the above, is there a function like "called-by" to do something like this:
(define lat?
(lambda (l)
(cond
((and (null? l) (called-by "lat?")) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
The usual way to do this is to add some argument to the function, or make a loop via an internal definition as you did. Other than that, there is no reliable way to find out the caller of a function.
But in your case, it seems like a good lack of feature -- using it for the above problem is pretty bad. There's nothing wrong with the internal helper version. (It's also quite similar to any other language.)
Finally, I'd expect (lat? null) to return #t since it is a list that has only atoms as elements.

Scheme evaluation order standard

I've got a program I'm writing for a class to substitute the left-most occurrence of a variable with a new variable. (It actually allows you to provide an equivalence relation yourself, as well). The thing is, in Chez Scheme 8.2, this substitutes the right-most occurrence, if the left most is inside a list. We use a server running some version of scheme (I'm not sure which version), and on the server it substitutes, correctly, the left-most occurrence. Below is the code:
(define subst-leftmost
(lambda (new old ls proc)
(let ([keep-going? #t])
(letrec ([helper
(lambda (ls)
(cond [(null? ls) ls]
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
[(and keep-going? (proc old (car ls)))
(set! keep-going? #f) (cons new (cdr ls))]
[else (cons (car ls) (helper (cdr ls)))]))]) (helper ls))))
This is called like so: (subst-leftmost 'x 'a '(d b c (a) b a) eq?) which should produce the output (d b c (x) b a), and does on the server. In Chez scheme, however, it produces (d b c (a) b x). I think the difference is due to the line
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
evaluating the helper of the car and the helper of the cdr in a not-set order.
My question is this: Which version of scheme is following the standard, and how can I modify my code so that it works correctly in both versions?
(I've already talked to my professor about this. He's going to address the class about it on Monday, once he can think about it some, but I'm curious. I also already got the full points for the assignment, so don't worry about the ethics of helping me, in that regard.)
There isn't any, sorry. Here's the relevant legalese. Use LETs or LET* if you need to evaluate sub-expressions in a particular order.
Scheme guarantees no specific order (as Cirno has said). If your code has no side-effects, this doesn't matter.
However, your code is side-effecting (because of the set! to an outside variable), so, you have some choices:
Use Racket (which is committed to using left-to-right order, last time I talked to a Racket dev)
Structure your code to remove side-effects, so that your helper function doesn't change any variable or state outside it
Use appropriate lets to ensure the ordering you need (as Cirno suggested); in particular, change (cons (helper (car ls)) (helper (cdr ls))) to:
(let ((depth-first (helper (car ls))))
(cons depth-first (helper (cdr ls))))

Resources