Applying a call only once in a recursive method in SCHEME - scheme

I have this method I wrote
(define (lev n L)
;(set! L(apply append L))
(cond ((null? L) '())
((eq? n (car (car L))) (car L))
(else (lev n (cdr L)))))
I want to apply the 'set!' only once before recursion and be done with it. I can't think of how to do this.

Try this:
(define (lev n L)
(let loop ((L (apply append L)))
(cond ((null? L) '())
((eq? n (car (car L))) (car L))
(else (loop (cdr L))))))
Here we're using a named let for defining a helper procedure inside lev (in this example, it's called loop), and before calling it we apply append to the input list and assign it to a new variable, also called L. In this case it's not necessary to use set!, in idiomatic Scheme we tend to avoid mutation operations.

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)))))))

Recurring with anonymous functions Common Lisp vs. Scheme

I'm working through the Little Schemer and I'm trying to convert all of the answers into Common Lisp.
In chapter 8, anonymous functions are discussed, as well as returning anonymous functions.
For example:
(define insertL-f
(lambda (test?)
(lambda (new old l)
(cond
((null? l) (quote ()))
((test? (car l) old) (cons new l)))
(else (cons (car l) ((insertL-f test?) new old (cdr l))))))))
My code:
(defun insertL-f (test)
(lambda (new old l)
(cond
((null l) '())
((funcall test (car l) old) (cons new l))
(t (cons (car l) (insertL-f test) new old (cdr l))))))
The problem is the last line of the second block of code. I get the error "too many arguments for cons" but I can't add an extra pair of parentheses like the Scheme code does. Is this style of recursion just not possible in Common Lisp?
(defun insertL-f (test)
(lambda (new old l)
(cond
((null l) '())
((funcall test (car l) old) (cons new l))
(t (cons (car l)
(funcall (insertL-f test)
new
old
(cdr l)))))))
insertL-f returns a function and in your Scheme version you apply it while in CL have flattened the list instead if applying it with funcall However it seems like the function that is to be returned is equal to the one it fetches so you can cache it by defining it locally with labels:
(defun insert-l-f (test)
(labels ((func (new old l)
(cond
((null l) '())
((funcall test (car l) old) (cons new l))
(t (cons (car l) (func new old (cdr l)))))))
#'func))
The same in Scheme using local define (which really is aletrec with flatter syntax):
(define (insert-l-f test?)
(define (func new old l)
(cond
((null? l) (quote ()))
((test? (car l) old) (cons new l)))
(else (cons (car l) (func new old (cdr l)))))
func)

How to reverse nested lists in Scheme

Consider:
(define (nested-reverse lst)
(cond ((null? lst) '())
((list? (car lst)) (nested-reverse (car lst)))
(else
(cons (nested-reverse (cdr lst))
(list (car lst))))))
When I input,
(nested-reverse '((a b c) 42))
it gives me ((() 42) (a b c)). It's supposed to give me (42 (c b a)). How I would change my code so that the nested lists also get reversed?
Keep in mind that a list (1 2 3) is (cons 1 (cons 2 (cons 3 '()))). Using append is a very poor choice on how to reverse a list since append is implemented like this:
(define (append lst1 lst2)
(if (null? lst1)
lst2
(cons (car lst1) (append (cdr lst1) lst2))))
A list can be iterated from the first element towards the end while it can only be made in reverse. Thus the obvious none recursive reverse would look like something like this:
(define (simple-reverse lst)
(let loop ((lst lst) (result '()))
(if (null? lst)
result
(loop (cdr lst) (cons (car lst) result)))))
To make it work for nested list you check if you need to reverse (car lst) by checking of it's a list or not and use the same procedure as you are creating to do the reverse on the element as well. Other than that it's very similar.

Scheme - application: not a procedure error

I'm coding a function in scheme but I'm getting a "application: not a procedure;
expected a procedure that can be applied to arguments" error. I assume that I haven't used the conditional statements correctly:
(define find-allocations
(lambda (n l)
(if (null? l)
'()
(cons ((if (<=(get-property (car l) 'capacity) n)
(cons (car l) (find-allocations (- n (get-property (car l) 'capacity)) (cdr l)))
'()))
(if (<=(get-property (car l) 'capacity) n)
(cons (car l) (find-allocations (n (cdr l))))
'())))))
If anyone can point out my error that'd be much appreciated.
Try this:
(define find-allocations
(lambda (n l)
(if (null? l)
'()
(cons (if (<= (get-property (car l) 'capacity) n)
(cons (car l) (find-allocations (- n (get-property (car l) 'capacity)) (cdr l)))
'())
(if (<= (get-property (car l) 'capacity) n)
(cons (car l) (find-allocations n (cdr l)))
'())))))
It's a very common mistake when learning Scheme: writing unnecessary parentheses! Remember: in Scheme a pair of () means function application, so when you write something - anything like this: (f), Scheme tries to apply f as if it were a procedure, in your code you had a couple of places where this was happening:
((if (<=(get-property (car l) 'capacity) n) ; see the extra, wrong ( at the beginning
(find-allocations (n (cdr l)))) ; n is not a function, that ( is also mistaken

Quicksort in scheme

please, what is bad in my code ? how can i modify that ?
(define pivot (lambda (l)
(cond ((null? l) 'done)
((null? (cdr l)) 'done)
((<= (car l) (cadr l)) (pivot (cdr l)))
(#t (car l)))))
(define (quicksort l)
(let ((piv (pivot l)))
(if (equal? piv 'done) l
(let ((parts (partition piv l () ())))
(append (quicksort (car parts))
(quicksort (cadr parts)))))))
Some Scheme interpreters define a partition procedure, but it receives a different set of parameters, so I'm assuming that you defined your own version. The implementation of quicksort shown in the question might work, but the partition procedure is almost certainly wrong. It's hard to tell without the code...

Resources