Scheme recursion error - scheme

This recursive function seems to work properly, adding to the result list the exact letters I want it to, B and C, and then when it finishes, it correctly sees that the last element has been reached.
It then executes the base case, and an error occurs which I cannot explain. What is causing this error?
(define(preceding-R X Vector result)
(if (eq? '() (cdr (vector->list Vector)))
result
(helper X Vector result)))
(define (helper X Vector result)
(if(eqv? X (cadr (vector->list Vector))) ((set! result (cons result (car (vector->list Vector)))) (preceding-R X (list->vector (cdr (vector->list Vector))) result))
(preceding-R X (list->vector (cdr (vector->list Vector))) result)))
(preceding-R 'a #(b a c a) '()))
The error:
procedure application: expected procedure, given: #; arguments were: ((() . b) . c)

Here's some code that isn't "absolutely horrible":
(define preceding-R
(lambda (x vec)
(define helper
(lambda (ls)
(cond
((null? ls) '())
((null? (cdr ls)) '())
((eq? (cadr ls) x) (cons (car ls) (helper (cdr ls))))
(else (helper (cdr ls))))))
(helper (vector->list vec))))
> (preceding-R 'a #(b a c a))
(b c)
Eli Barzilay has a point; if I were grading the original code, I would probably award fewer than half credit because of the things he pointed out:
set! should be avoided in most circumstances, and is generally not permitted on homework problems involving basic Scheme code. Having to use set! is a usual tell that recursion isn't understood too well.
Since begin "throws away" the results of everything but the last expression, it means that the non-tail expressions had side-effects (like set!) and so begin usually doesn't show up in educational problems either.
Conversion back-and-forth over and over and over and over again is obviously a waste. One conversion will do, but you probably could've used lists instead of vectors to begin with. Lists are the most common data structure used in Scheme, especially since they work well with recursion.
Your code will error out on an empty list in your second line: (preceding-R 'a #()) => Error: Attempt to apply cdr on '()
If you do use set! to modify result, then there's no reason to pass result around. It's extra baggage.
Eli's last point was that you can write:
.
(define (helper X Vector result)
(preceding-R X (list->vector (cdr (vector->list Vector)))
(if (eq? X (cadr (vector->list Vector)))
(cons (car (vector->list Vector)) result)
result)))
saving some repeated code.

(define (preceding-R X Vector result)
(if (eq? '() (cdr (vector->list Vector)))
result
(helper X Vector result)))
(define (helper X Vector result)
(if (eqv? X (cadr (vector->list Vector)))
(begin
(set! result (cons (car (vector->list Vector)) result))
(preceding-R X (list->vector (cdr (vector->list Vector))) result))
(preceding-R X (list->vector (cdr (vector->list Vector))) result)))
(preceding-R 'a #(b a c a) '())
I've added begin call. If you want multiple expressions in if you can't just wrap them in (), it was interpreted as function call on void (returned by set!) with argument returned by recursive call to preceding-R.

Related

Scheme with postfix

Does anyone can help me to deal with the problem?
I tried for many times, but it still has the error information.
This is my code(scheme)
Thanks!!!
(define (postfix l s)
(cond(
((null? l)(car s))
(else (postfix (cdr l) update-s((car s)))))))
(define (update-s x s)
(cond(((number? x) (cons x s))
(else (cons (eval '(x (car s) (cadr s))) (scheme-report-environment 5) (cdr(cdr s)))))))
And this is the error inform:
else: not allowed as an expression in: (else (postfix (cdr l) update-s ((car s) s)))
Next time, don't forget to add a description of your problem (what should this code do?), expected inputs and outputs, and a version of Scheme you use.
You should also use better names for variables (no l, s, x) and describe their meaning and expected type in your question.
If I understand correctly, you were trying to create a calculator which uses reverse Polish/ postfix notation, where:
l is a list of numbers or symbols
s is a stack with results, represented as a list of numbers
x can be a number or symbol representing some function
From (scheme-report-environment 5) I guess you use r5rs Scheme.
Now some of your errors:
you should define update-s before function postfix
your cond has some additional parentheses
if cond has only two branches, you should use if instead
this part (postfix (cdr l) update-s((car s))) should be (postfix (cdr l) (update-s (car l) s)
(cdr(cdr s)) should be (cddr s)
as for eval, I understand why it's here, you were trying to get a function from the symbol, but you should be always careful, as it can also evaluate code provided by user. Consider this example: (postfix '(1 2 (begin (write "foo") +)) '()). Maybe it could be better to don't expect this input: '(1 2 +), but this: (list 1 2 +) and get rid of eval.
The whole code:
(define (update-s object stack)
(if (number? object)
(cons object stack)
(cons ((eval object (scheme-report-environment 5))
(car stack) (cadr stack))
(cddr stack))))
(define (postfix lst stack)
(if (null? lst)
(car stack)
(postfix (cdr lst)
(update-s (car lst) stack))))
Example:
> (postfix '(1 2 +) '())
3
Solution without eval with different input:
(define (update-s object stack)
(if (number? object)
(cons object stack)
(cons (object (car stack) (cadr stack))
(cddr stack))))
(define (postfix lst stack)
(if (null? lst)
(car stack)
(postfix (cdr lst)
(update-s (car lst) stack))))
Example:
> (postfix (list 1 2 +) '())
3

Lists traversal in Scheme

myList is a list with elements both as symbols or lists of the same type of myList.
For example: myList = '(a b (a d c) d ()) , etc.
I want to write a function in Scheme which would just traverse it (eventually I will replace the symbols with other values).
I wrote this function:
(define traversal (lambda (myList)
(if (null? myList) '()
(if (and (list? (car myList)) (not (null? (car myList))))
(list (traversal (car myList)) (traversal (cdr myList)))
; else if car is an empty list
(if (null? (car myList))
(list (traversal (cdr myList)))
; else car is a symbol
(append (list (car myList)) (traversal (cdr myList))))))))
It gives correct results for some configuration of myList, but definitely it is not the one.
For example,
(display (traversal '((f) h (r t b) (x m b m y) b (c (d)))))
adds additional paranthesis which I don't need.
What would be a correct way to display such a list?
You're testing null? in so many places, where one test is generally enough.
You rarely use list in these traversals, but simply cons.
Also, append is best avoided, and not needed here.
Repetitive use of (car ...) is optimised with a let form.
The simplified form of your code would be:
(define traversal
(lambda (myList)
(if (null? myList)
'()
(let ((c (car myList)))
(cons (if (list? c) (traversal c) c)
(traversal (cdr myList)))))))
EDIT
While this procedure works well for proper lists, it doesn't correctly work for improper lists (although it appears to). The following is a more general approach that works for every kind of S-expression, including proper lists, and I recommend this over the previous code:
(define traversal
(lambda (sexp)
(cond
((null? sexp) '())
((pair? sexp) (cons (traversal (car sexp))
(traversal (cdr sexp))))
(else sexp))))
You are close to the solution. Here are a few hints:
Instead of nested ifs try using the cond form, it is more readable.
The expression (and (list? (car myList)) (not (null? (car myList)))) is correct, but you may use (pair? (car myList)) which is shorter and does almost the same thing.
traversal should return a list but using list with list arguments here
(list (traversal (car myList)) (traversal (cdr myList)))
will return a list of lists. E.g. (list '(a) '(b)) will return ((a) (b)) instead of (a b). In these cases you should use append (append '(a) '(b)) -> (a b).
If a value is not a list but you want to add it to an existing list, use the cons procedure.
(cons 'a '(b c)) -> (a b c).

How to determine if a list has an even or odd number of atoms

tScheme novice question:
I need to determine if a list contains an even or odd amount of atoms using recursion. I know the easy way is to get list length and determine if it is even or odd, but I would like to see hows it's done using recursion.
(oddatom
(LIST 'x 'y 'v 'd 'r 'h 'y))
should return #t, while
(oddatom
'((n m) (f p) l (u k p)))
should return #f
appreciate the help.
Here's my version of the solution:
(define (oddatom? lst)
(let recur ((odd #f)
(x lst))
(cond ((null? x) odd)
((pair? x) (recur (recur odd (car x)) (cdr x)))
(else (not odd)))))
I like Chris Jester-Young's answer, but I think it's worth providing a tail-recursive version that maintains its own stack as well. Note that this is an exercise in converting non-tail recursion into tail recursion, which is an imporant technique for some algorithms in Scheme. In this case, though, it's probably not all that important, and the code in Chris Jester-Young's answer does feel much more natural. So take this as an exercise, not necessarily a significant improvement.
The idea here is that the inner function, odd?, takes a list of things, and a value indicating whether an odd number of atoms (other than the empty list) have been seen so far.
(define (oddatom? thing)
(let odd? ((things (list thing))
(result #f))
(cond
;; We're out of things to see. Did we see an odd number of things?
((null? things)
result)
;; Our list of things has the form ((x . y) …), so we recurse on
;; (x y …), with the *same* value for result, since we haven't
;; "seen" x or y yet, we've just "unwrapped" them.
((pair? (car things))
(odd? (cons (caar things) (cons (cdar things) (cdr things))) result))
;; Our list of things has the form (() …), so we recurse on
;; (…), with the *same* value for result, since we haven't "seen" any
;; additional atoms.
((null? (car things))
(odd? (cdr things) result))
;; Our list of things has the form (<atom> …), so we recurse on (…),
;; but with a flipped value for result, since we've seen one more atom.
(else
(odd? (cdr things) (not result))))))
The last two cases could be combined, making the second recursive argument based on the value of (null? (car things)) as:
(define (oddatom? thing)
(let odd? ((things (list thing))
(result #f))
(cond
((null? things)
result)
((pair? (car things))
(odd? (cons (caar things) (cons (cdar things) (cdr things))) result))
(else
(odd? (cdr things) (if (null? (car things))
result
(not result)))))))
I'd go for this:
(define (oddatom lst)
(cond
((null? lst) #f)
((not (pair? lst)) #t)
(else (not (eq? (oddatom (car lst)) (oddatom (cdr lst)))))))
which means:
the empty list is not odd (#f)
an atom is odd (#t)
otherwise, one and only one of the car or the cdr of the list may be odd (exclusive or).
Test cases (in Racket), including improper lists:
(require rackunit)
(check-equal? (oddatom (list 'x 'y 'v 'd 'r 'h 'y)) #t)
(check-equal? (oddatom '((n m) (f p) l (u k p))) #f)
(check-equal? (oddatom '(a (b) c)) #t)
(check-equal? (oddatom (cons 1 2)) #f)
(check-equal? (oddatom 1) #t)
(check-equal? (oddatom '(1 (2 . 3))) #t)
Here is one:
(define (odd-atom? obj)
(and (not (null? obj))
(or (not (pair? obj))
(let ((this? (odd-atom? (car obj)))
(rest? (odd-atom? (cdr obj))))
(or (and (not this?) rest?)
(and (not rest?) this?))))))
or, learning from #uselpa to simplify the 'or this? rest?' logic above, another one:
(define (odd-atom? obj)
(and (not (null? obj))
(or (not (pair? obj))
(not (eq? (odd-atom? (car obj))
(odd-atom? (cdr obj)))))))
If '() is an atom (like it is in CommonLisp where '() is also T), it should be (odd-atom? '(() () ())) is #t:
(define (odd-atom? obj)
(and (not (null? obj))
(or (not (pair? obj))
(let ((this? (or (null? (car obj))
(odd-atom? (car obj))))
(rest? (odd-atom? (cdr obj))))
(not (eq? this? rest?))))))
> (odd-atom? '())
#f
> (odd-atom? '(()))
#t
> (odd-atom? '(() () ()))
#t
> (odd-atom? '(() ()))
#f
> (odd-atom? '(() (a)))
#f
> (odd-atom? '(() (a b)))
#t
> (odd-atom? '((a) (a b)))
#t
> (odd-atom? '((a b) (a b)))
#f
>

scheme - equal function with lists

I wrote this program:
(define find-combination
{lambda (a b)
(if (eq? ((quotient (car a) (car b)) (quotient (car (cdr a)) (car (cdr b)))))
(display "1*v1" + ((quotient (car a) (car b))*"v2"))
(display "0*v1" + "0*v2"))})
(find-combination (list 2 2) (list 2 1))
a and b are two lists. Its give me the next problem: procedure application: expected procedure, given: 1; arguments were: 2.
I didn't get what is the problem. Someone can help me? Thank u.
First of all you have too much brackets after eq? - what you wrote means evaluating (quotient (car a) (car b)) and treating it as a function with argument (quotient (car (cdr a)) (car (cdr b))). The error means that first thing was evaluated to 1 and your interpreter expected it to be a procedure, not an integer. This line should be:
(if (eq? (quotient (car a) (car b)) (quotient (car (cdr a)) (car (cdr b))))
or even:
(if (eq? (quotient (car a) (car b)) (quotient (cadr a) (cadr b)))
Apart from that, lines with display calls are wrong - Scheme doesn't have an infix notation, so + and * are out of place.
First of all you have a set of curly braces in your code(the one before lambda)
Also you have another set of paranthesis around the parameters you passed to eq?
It should be something like this:
(eq? (quotient (car a) (car b)) (quotient (car (cdr a)) (car (cdr b))))
In Scheme and Racket, parentheses change the meaning of things.
1
is a number, but
(1)
is a call to 1 as a function... but 1 is a number, not a function, so this will cause the error you describe.
Your use of curly braces is also a little unsettling to me.

how to define last in scheme?

how can I write a function to take the last element of the list?
find the last of a list:
(define (last l)
(cond ((null? (cdr l)) (car l))
(else (last (cdr l)))))
use map to map last to a list:
(map last '((a b) (c d) (e f)))
==> (b d f)
so a new function:
(define (last-list l)
(map last l)
)
(last-list '((a b) (c d) (e f)))
==> (b d f)
May not be the most efficient, but certainly one of the simplest:
(define (last lst)
(car (reverse lst)))
Examples:
(last '(1 2 3 4)) => 4
(last '((a b) (b c) (d e))) => (d e)
The code you've written - to take the last element of a list - is correctly returning the last element of the list. You have a list of lists. There is an outer list
(x y z)
where
x = (a b)
y = (c d)
z = (e f)
So you're getting the last element of the list, z, which is (e f)
Did you want your last function to do something different? If you want it to return the last element of the last nested list, you need to change your base case. Right now you return the car. Instead, you want to check if the car is a list and then call your nested-last function on that.
Make sense?
Your last function is good, but you have to think about what you want to do with it now.
You have a list of lists, and you want to take the last of all those.
So recurse down your list applying it each time:
(define (answer lst)
(cond ((null? (cdr l)) null)
(else (cons (last (car l)) (answer (cdr lst))))
Yet another possibility:
(define (last thelist)
(if
(null? (cdr thelist)) (car thelist)
(last (cdr thelist))))
(define (all-last lists) (map last lists))
Edit: just saw that you don't know map, and want a solution without it:
(define (all-last lists)
(if
(null? lists) `()
(cons (last (car lists)) (all-last (cdr lists)))))
As far as getting an empty list goes, I'd guess you're trying to use this map-like front-end with your original definition of last, whereas it's intended to work with the definition of last I gave above. Try the following definitions:
(define (last thelist) (if
(null? (cdr thelist)) (car thelist)
(last (cdr thelist))))
(define (all-last lists) (if
(null? lists) `()
(cons (last (car lists)) (all-last (cdr lists)))))
and running a quick test:
(all-last `((a b) (c d) (e f)))
The result should be:
(b d f)
(define last
(lambda (ls)
(list-ref ls (- (length ls) 1))))
I like short, sweet, fast, tail-recursive procedures.
Named let is my friend.
This solves the original problem and returns #f if the list has no last element.
(define (last L) (let f ((last #f) (L L)) (if (empty? L) last (f (car L) (cdr L)))))
The best way to get what you want:
(define (last lst)
(cond [(empty? lst) empty]
[(empty? (rest lst)) (first lst)]
[else (last (rest lst))]))

Resources