How to create a function that receives a list and creates a new list in Scheme - scheme

I'm trying to create a function called evenElememt that takes a list as a parameter and appends all the elements in even positions to a new list and displays the new list.
My attempt:
(define newList '())
(define elementHelper
(lambda lst
((cdr lst)
(cons newList (car lst))
(elementHelper(cdr lst)))
)
)
(define evenElement
(lambda (lst)
(cond
((null? lst) ())
((null? (cdr lst)) ())
(else (elementHelper lst)
(display lst))
)
)
)
Example output: if I enter (evenElement '('a 'b 'c 'f 't 'y)), the output should be (b f y).

This is essentially the same as Can I print alternate elements of a list in Racket?, except that you want to print even positions (1-indexed) instead of odd positions.
(define (even-positions lst)
(cond ((null? lst)
'())
((null? (cdr lst))
'())
(else
(cons (second lst)
(even-positions (cddr lst))))))
(even-positions '(a b c f t y)) returns '(b f y).
Then, this is the function you are looking for:
(define (display-even-positions lst)
(display (even-positions lst)))

You don't need elementHelper. Just make evenElement return the result instead of displaying it.
You also don't need the global variable newList. The function should construct the result as it goes.
(define evenElement
(lambda (lst)
(cond
((null? lst) '())
((null? (cdr lst)) '())
(else (cons (car (cdr lst))
(evenElement (cdr (cdr lst)))))
)
)
)
(display (evenElement '(a b c f t y)))

Related

Is there anything wrong with my "sum of list" code in scheme?

My else statement line is giving me an error. Is any of my other line of codes affecting the else expression?
(define (sumAdd list)
(cond
((null? list) '())
((null? (cdr list)) list)
((symbol? list) sumAdd(cdr list))
(else (+ (car list)(sumAdd (cdr list))))
)
)
If I understand correctly, you want to sum all the numbers in a list with mixed element types. If that's the case, there are several errors in your code:
(define (sumAdd list) ; `list` clashes with built-in procedure
(cond
((null? list) '()) ; base case must be zero for addition
((null? (cdr list)) list) ; why discard the last element?
((symbol? list) sumAdd(cdr list)) ; that's not how procedures are called
(else (+ (car list) (sumAdd (cdr list)))))) ; this line is fine :)
This is the correct way to implement the procedure:
(define (sumAdd lst)
(cond
((null? lst) 0) ; base case is zero
((symbol? (car lst)) (sumAdd (cdr lst))) ; skip current element
(else (+ (car lst) (sumAdd (cdr lst)))))) ; add current element
It works as expected:
(sumAdd '(1 a 2 b 3 c))
=> 6

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

Racket program not working as it should

i made a function which takes a list and two elements of the list. It should return #t if the second argument appears in the list argument before the third argument:
The procedure should also return #f if either of the supposed elements doesn't appear at all.
here is what I got so far:
(define (before-in-list? lst a b )
(cond
((empty? lst ) #f)
((eq? (car lst ) a) ( map b (cdr lst)) #t)
((eq? (car lst ) b) #f)
(else (before-in-list? (cdr lst ) a b ))))
to test it, i used:
(before-in-list? '(back in the ussr) '(in) '(ussr))
(before-in-list? '(back in the ussr) '(the) '(ussr))
the problem is that it gives me f every time.
any tips on how to fix it please?
The way you're using map doesn't make sense. Also, you should use equal? for more general comparisons, and the a and b parameters should not be lists. Try this:
(define (before-in-list? lst a b)
(cond
((empty? lst ) #f)
((equal? (car lst) a)
(if (member b (cdr lst)) #t #f))
((equal? (car lst) b) #f)
(else (before-in-list? (cdr lst ) a b))))
(before-in-list? '(back in the ussr) 'in 'ussr)
=> #t
(before-in-list? '(back in the ussr) 'the 'ussr)
=> #t

SCHEME Mutable Functions

I've been self-teaching myself Scheme R5RS for the past few months and have just started learning about mutable functions. I've did a couple of functions like this, but seem to find my mistake for this one.
(define (lst-functions)
(let ((lst '()))
(define (sum lst)
(cond ((null? lst) 0)
(else
(+ (car lst) (sum (cdr lst))))))
(define (length? lst)
(cond ((null? lst) 0)
(else
(+ 1 (length? (cdr lst))))))
(define (average)
(/ (sum lst) (length? lst)))
(define (insert x)
(set! lst (cons x lst)))
(lambda (function)
(cond ((eq? function 'sum) sum)
((eq? function 'length) length?)
((eq? function 'average) average)
((eq? function 'insert) insert)
(else
'undefined)))))
(define func (lst-functions))
((func 'insert) 2)
((func 'average))
You're not declaring the lst parameter in the procedures that use it, but you're passing it when invoking them. I marked the lines that were modified, try this:
(define (lst-functions)
(let ((lst '()))
(define (sum lst) ; modified
(cond ((null? lst) 0)
(else
(+ (car lst) (sum (cdr lst))))))
(define (length? lst) ; modified
(cond ((null? lst) 0)
(else
(+ 1 (length? (cdr lst))))))
(define (average)
(/ (sum lst) (length? lst)))
(define (insert x)
(set! lst (cons x lst)))
(lambda (function)
(cond ((eq? function 'sum) (lambda () (sum lst))) ; modified
((eq? function 'length) (lambda () (length? lst))) ; modified
((eq? function 'average) average)
((eq? function 'insert) insert)
(else
'undefined)))))
Now it works as expected:
(define func (lst-functions))
((func 'insert) 2)
((func 'average))
=> 2
((func 'sum))
=> 2
((func 'length))
=> 1
Some of your functions are recursive but defined without argument. Thus (sum (cdr lst)) shouldn't work since sum uses lst. You could do it by defining a helper:
(define (sum-rec lst)
(if (null? lst)
0
(+ (car lst) (sum-rec (cdr lst)))))
Or perhaps with an accumulator:
(define (sum-iter lst acc)
(if (null? lst)
acc
(sum-iter (cdr lst) (+ (car lst) acc)))
Your sum would of course use it passing the lst:
(define (sum)
(sum-iter lst 0))
Or you can just have the driver partial apply them like this:
(lambda (function)
(cond ((eq? function 'sum) (lambda () (sum-iter lst))
...))
A side note. length? is a strangely named function. A question mark in the end of a name is usually reserved for functions that return a true or a false value and this clearly returns a number.

Remove duplicates from a list in Scheme

I need to remove consecutive duplicates from a list in Scheme for ex:
(remove '(e f f g h h e e))
should return
(e f g h e)
This is what I have but I keep getting an error:
(define (remove lst)
(cond
((null? lst '())
((null? (cdr lst)) '())
((equal? (car lst)(car(cdr lst)))(remove(cdr lst)))
(cons(car lst)(remove (cdr lst))))))
I thought I was on the right track but I can't see what I'm doing wrong.
The parentheses are incorrect in the first case, and in the last case you forgot to write the else. Also, the second case is incorrect; this is what I mean:
(define (remove lst)
(cond
((null? lst) '())
((null? (cdr lst)) lst)
((equal? (car lst) (car (cdr lst))) (remove (cdr lst)))
(else (cons (car lst) (remove (cdr lst))))))

Resources