How to fix this code in Scheme, where I am trying to find the last two elements in the list - scheme

I am trying to write a code in scheme -last_two(lst) where it should output the last two elements in the list.
(define (last_two lst)
(if (null? lst)
'() )
(if (null? (cdr lst))
lst)
(if(null? (cddr lst)))
lst)
(last_two (cdr lst)))
last_two(1 2 3 4) -> (3 4)

A procedure returns the value of the last expression that's executed in the body. In your procedure, when one of the first if conditions is true, you don't return the value from the procedure, you just go on to test the next condition. Eventually you get to the end, which is the recursive call -- you never stop at the base case. Eventually you'll get an error when you try to call (cdr lst) on an empty list.
You can use cond to test a series of conditions and return the value from the first one that's true.
Also, you should be returning lst when the conditions match; your code will always return (), since you're returning the same thing that matched the null? condition.
(define (last_two lst)
(cond ((null? lst) '())
((null? (cdr lst)) lst)
((null? (cddr lst)) lst)
(else (last_two (cdr lst)))))
(last_two '(1 2 3 4))
You might notice that the first 3 conditions all return lst, so you could combine them using or.
(define (last_two lst)
(if (or (null? lst) (null? (cdr lst)) (null? (cddr lst)))
lst
(last_two (cdr lst))))

Related

How to check if first and last element in a list are identical (Language: Scheme)

I am writing a program in Scheme and having difficulty with this one part. Below is an example to make my question clear
(endsmatch lst) should return #t if the first element in the list is the same as the last element in the list and return #f otherwise.
For example:
(endsmatch '(s t u v w x y z)) should return: #f
and
(endsmatch (LIST 'j 'k 'l 'm 'n 'o 'j)) should return: #t
Here is what I have so far (just error handling). The main issue I am having is solving this recursively. I understand there are easier solutions that are not recursive but I need to solve this using recursion.
My code so far:
(define (endsmatch lst)
(if (not(list? lst))
"USAGE: (endsmatch [list])"
(if (or (null? lst)
(= (length lst) 1))
#t
(equal? ((car lst)) (endsmatch(car lst)))
)))
I believe my code starting at "(equal? " is where it is broken and doesn't work. This is also where I believe recursion will take place. Any help is appreciated!
Easiest way is to use a (recursive) helper function to do the looping:
(define (endsmatch lst)
(define (helper no1 lst)
(if (null? (cdr lst))
(equal? no1 (car lst))
(helper no1 (cdr lst))))
(if (or (not (list? lst)) (null? lst))
"USAGE: (endsmatch [list])"
(helper (car lst) lst)))
The reason I pass lst and not (cdr lst) as the second argument in the last line is so that it also works for 1-element lists.
I tend to use KISS when programming. aka. "Keep it simple, stupid!"
With that regard I would have oped for:
(define (ends-match? lst)
(or (null? lst)
(equal? (car lst)
(last lst))))
Now last we can define like this:
(define (last lst)
(foldl (lambda (e a) e) last lst))
It's not perfect. It should signal an error if you pass an empty list, but in the ends-match? you check for this and thus it's not a problem.

Scheme, can someone explain how I'm using set-car! wrong?

I wanted to make a procedure that destructively increments the odd numbers of a list. I thought I'd recurse through it and just use 'set-car!' whenever 'odd?' was true.
Here is the code:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
I'm not sure why it is not working, I guess I do not understand set-car! and set-cdr!
Could someone explain? Thank you.
The problem might be with your interpreter, or the language in which you're defining the procedure, or the way you're calling it. For instance, in DrRacket this works fine:
#lang r5rs
(define (test lst)
(cond ((null? lst) lst) ; this is the '() returned by the recursion
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
Bear in mind that your procedure will return an empty list, because that's the base case of the recursion and this is a tail-recursive procedure, which returns the value at the base case as its final result. But don't worry, the input list was modified in-place, you can check it after the procedure returns its value.
(define lst (list 1 2 3 4))
(display (test lst))
=> ()
(display lst)
=> (2 2 4 4)
See how mutability is confusing? a procedure is returning one value, but its input was modified and has a different value now. That's one of the reasons why functional programming (which favors immutable data) is cleaner and simpler to understand, and also demonstrates why is a bad idea to mutate input parameters inside a procedure ;)
If you absolutely want the procedure to return the mutated list, do as #sepp2k suggests, but remember - the input list was modified and in fact, is the same list that is returned as a result:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst))
lst) ; add this line
(else (test (cdr lst)))))
See for yourself:
(define lst (list 1 2 3 4))
(display (test lst))
=> (2 2 4 4)
(display lst)
=> (2 2 4 4)
was expecting the have the list containing (2 2 4 4) returned
The way you defined your function, it will return an empty list when called on the empty list and the result of the recursion in all other cases. So since the only base case is the empty list, you'll always return the empty list.
If you want to return the modified list, you'll need to do that after the recursion. That is after (test (cdr lst)), add lst to return the value of lst.
You are using set-car! correct. Here is how you tell it's working:
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(define test-list (list 1 2 3 4))
(test test-list)
test-list ; ==> (2 2 4 4)
Your expectation that the function will return the modified list is wrong. To do that you need the first recursion step to return the argument. You need to wrap it:
(define (inc-odds lst)
(define (test lst)
(cond ((null? lst) lst)
((odd? (car lst)) (set-car! lst (+ (car lst) 1))
(test (cdr lst)))
(else (test (cdr lst)))))
(inc-odds lst) ; do the stuff
lst) ; return the list
(inc-odds (list 1 2 3 4)) ; ==> (2 2 4 4)
(inc-odds '(1 2 3 4)) ; ==> "pigs flying"
Notice the last one. In the RNRS upto R5RS passing a quoted literal to set-car! would produce an undefined behaviour which means anything is ok because technically the code isn't Scheme. In R6RS it's required to raise an exception.

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.

How to define Sets in scheme

I'm having trouble using my member? function. I need to recurse on my set? function until the last element in my list 'lst' is reached. I believe I have the navigation down correctly, but maybe my inputs syntax is wrong. I know there are three cases:
1) What happens if the list is empty? that means that there aren't any duplicates in it
2) What happens if the current element of the list exists somewhere in the rest of the list? then it means that there's a duplicate in the list (hint: the member procedure might be useful)
3) If none of the above are true, continue with the next element.
Here is my code.
(define (member? e lst)
(if (null? lst) #f
(if (equal? e (car lst)) #t
(member? e (cdr lst)))))
(define (set? lst)
(if (null? lst) #t ;Case1
(if (member? (car lst) lst) #f ;Case2
(set? (cdr lst))))) ;Case3
;Example tests for the set? function
(set? '(x y z))
(set? '(a 1 b 2 c 3))
(set? '())
(set? '(6 2 2))
(set? '(x y z x))
There's a small mistake with your code, look how it gets fixed:
(define (set? lst)
(if (null? lst)
#t
(if (member? (car lst) (cdr lst)) ; in here
#f
(set? (cdr lst)))))
In particular, notice what this line is doing:
(member? (car lst) lst)
That won't work: the test is checking whether the first element in lst is a member of lst - and that'll always be true. The solution is simple, just check to see if the current element is in the rest of the list, if it's there, then we know that we've found a duplicate:
(member? (car lst) (cdr lst))
And by the way, the above code would look much nicer using cond, which is great when you have nested ifs:
(define (set? lst)
(cond ((null? lst) #t)
((member? (car lst) (cdr lst)) #f)
(else (set? (cdr lst)))))

Printing elements of a list with odd indices in Scheme

so theres this code called ret-odds
ex: (define (ret-odds lst)
(if (null? lst) null
(if (null? (cdr lst)) null
(cons (car lst) (ret-odds (cdr (cdr lst)))))))
i know the problem is with the last line in that it skips over the second element of the list and gives only the 3rd.....
ex: (ret-odds (list 'a 'g 'e )) the procedure instead skips over the g and e and gives me null so i only end up with a so i was wondering how would i fix this?
Your code is always skipping the last element in the list:
On the first invocation with (list 'a 'd 'e), lst is non-null and (cdr lst) is non-null, so it takes the car ('a) and does a recursive call with the cddr (which is (list 'e))
On the second invocation with (list 'e), lst is non-null but (cdr lst) is null. So it returns null, skipping the 'e completely.
Something like this should work:
ex: (define (ret-odds lst)
(if (null? lst) null
(cons (car lst)
(if (null? (cdr lst)) null (ret-odds (cdr (cdr lst)))))))
Change null of your second if to lst.
(define (ret-odds lst)
(cond ((null? lst) lst)
((null? (cdr lst)) lst)
(else (cons (car lst) (ret-odds (cddr lst))))))

Resources