Scheme: Iterate Through Whole List - scheme

I have a program that takes in an input like '((1 plus 2) (2 times 2)). However, when I run that example input, it only prints out '(3). How can I change this code to parse through the whole list that I give it and not just the first instance in the list?
(define math
(lambda (lst)
(cond [(null? lst) lst]
[(equal? (second (car lst)) 'plus) (cons (+ (first (car lst)) (third (car lst))) '())]
[(equal? (second (car lst)) 'times) (cons (* (first (car lst)) (third (car lst))) '())])
))

You need to advance the recursion, so the procedure will continue with the rest of the expressions in the list. Try this:
(define math
(lambda (lst)
(cond [(null? lst) lst]
[(equal? (second (car lst)) 'plus)
(cons (+ (first (car lst)) (third (car lst)))
(math (cdr lst)))] ; advance the recursion
[(equal? (second (car lst)) 'times)
(cons (* (first (car lst)) (third (car lst)))
(math (cdr lst)))]))) ; advance the recursion
It works as expected:
(math '((1 plus 2) (2 times 2)))
=> '(3 4)

Related

How can i get the positive even elements in scheme

I am trying to get all the even and positive elements in scheme
I have the following code
(define (getVals lis)
(cond
((null? lis) lis)
(((> (car lis) 0) (even? (car lis)))
(cons (getVals (cdr lis))))
)
)
To check my code im using
getVals '(2 -2 4 6 5))
Which should output a new list with positive and even numbers (2 4 6)
Thank you
The simplest way would be to use built-in procedures:
(define (getVals lis)
(filter (lambda (x) (and (even? x) (positive? x)))
lis))
If you want to implement it from scratch, you need to fix your code:
It's missing the case where the current element does not meet the conditions (the else case).
It's missing one parameter when calling cons.
The condition is missing an and.
This is what I mean:
(define (getVals lis)
(cond
((null? lis) lis)
((and (even? (car lis)) (positive? (car lis)))
(cons (car lis) (getVals (cdr lis))))
(else (getVals (cdr lis)))))
Either way, it works as expected:
(getVals '(2 -2 4 6 5))
=> '(2 4 6)
And just to add to #OscarLopez's answer - if you have a second look you will see, that getVals is just the specific case of `filter.
(define (getVals lis)
(cond
((null? lis) lis)
((and (even? (car lis)) (positive? (car lis)))
(cons (car lis) (getVals (cdr lis))))
(else (getVals (cdr lis)))))
Versus:
(define (filter func lst)
(cond
((null? lis) lst)
((func (car lst))
(cons (car lst) (filter func (cdr lst))))
(else (filter func (cdr lst)))))
With filter func as getVales, and
with func as:
(lambda (x) (and (even? x) (positive? x)))
getVals is just a special case of filter:
(define (getVals lst)
(filter (lambda (x) (and (even? x) (positive? x))) lst))
But you should follow the style guide for Lisp languages -
don't use camelCase for function names but prefer the lisp-typic form get-vals.

Removing Duplicates from a list as well as the elements themselves- Racket, Scheme

(define (remove-duplicates l)
(cond ((empty? l)
'())
((member (first l) (rest l))
(remove-duplicates (rest l)))
(else
(cons (first l) (remove-duplicates (rest l))))))
This code has this result.
> (remove-duplicates (list 1 1 2 2 3 4))
(list 1 2 3 4)
Without using filter, I would like the result to be
(remove-duplicates (list 1 1 2 2 3 4)) gives
(list 3 4)
Help would be deeply appreciated. Thanks in advance.
You could use a helper function:
(define helper
(lambda (lst collector dup)
(cond [(null? lst) collector]
[(memq (car lst) (cdr lst)) (helper (cdr lst) collector (cons (car lst) dup))]
[(memq (car lst) dup) (helper (cdr lst) collector dup)]
[else
(helper (cdr lst) (cons (car lst) collector) dup)])))
Maintain two lst, collector for all unique element, and dup for duplicated elements.
(define remove-dup
(lambda (lst)
(reverse (helper lst '() '()))))

Racket Append Undesired Reversal of List

I wrote a small function that takes a list and returns a list composed of only positive numbers. This all works fine, but for some reason, it is reversing the order. More information below on that. Could someone please tell me if this is normal, or if I miss-wrote something? Thank you in advance.
(define (positive-nums-only lst)
(if (empty? lst)
'()
(append (positive-nums-only (cdr lst))
(if (>= (car lst) 0)
(list (car lst))
'()))))
(positive-nums-only '(1 2 -4 90 -4))
The above test case returns '(90 2 1)
You did not make a mistake, the program is making what you asked.
See, the program finishes the recursion calls first, before going into resolving the if statement. This causes the (list ... ) to start listing from the last element that is positive, in this example it will be 90.
Changing the code order will produce the result you want.
(define (positive-nums-only lst)
(if (empty? lst) '()
(append (if (>= (car lst) 0 )
(list (car lst))
'())
(positive-nums-only (cdr lst)))
)
)
On the other hand, this kind of recursion could be expensive to the computer. I'd use tail recursion, like this:
(define positive-nums-only-tail
(λ (lst r)
(cond ((empty? lst) (reverse r))
((positive? (car lst))
(positive-nums-only-tail (cdr lst)
(cons (car lst) r)))
(else (positive-nums-only-tail (cdr lst) r))
)
)
)
Have you tried reversing the append?
(define (positive-nums-only lst)
(if (empty? lst)
'()
(append (if (>= (car lst) 0) (list (car lst)) '())
(positive-nums-only (cdr lst)))))
Personally I find it more natural to write it like this:
(define (positive-nums-only lst)
(if (empty? lst)
'()
(let ((rest (positive-nums-only (cdr lst))))
(if (>= (car lst) 0)
(cons (car lst) rest)
rest))))

How to delete the 2nd to last element from a list in Scheme?

I'm using Scheme and I'm trying to remove the 2nd to last element in the list recursively.
This is what I have:
(define delete
(lambda (num lst)
(cond
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete num (cdr lst)))))))
(define second
(lambda(lst)
(delete (- (length lst) 1) lst)))
(second '(1))
(second '(3 5 6))
(second '(2 7 8 4 9))
returns this:
()
(3 5)
(2 7 8 4)
When it should return this:
()
(3 6)
(2 7 8 9)
The (second '(1)) is doing what I intended but I've playing with the other part for a few hours and I'm still at a loss. Any tips or suggestions would be very appreciated at this point.
EDIT:
Wow, Thank you! It was that one line of missing code -_- Duh me!
You never use the num argument. So you will always iterate until the list has 1 element or is null. You could add a special case for when the list has 2 elements:
(define delete
(lambda (num lst)
(cond
((equal? (length lst) 2) (cdr lst))
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete num (cdr lst)))))))
(define second
(lambda(lst)
(delete (- (length lst) 1) lst)))
Since the num argument isn't used, you can do:
(define delete_second_last
(lambda (lst)
(cond
((equal? (length lst) 2) (cdr lst))
((equal? (length lst) 1) '())
((null? lst) '())
(else (cons (car lst)(delete_second_last (cdr lst)))))))
(delete_second_last '(3 6 7 9 10))

List order after duplicate filtering

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.
(define (inlist L n)
(cond
((null? L) #f)
((= (car L) n) #t)
(else (inlist (cdr L) n))
))
(define (uniquelist L)
(cond
((null? L) '())
((= 1 (length L)) L)
((inlist (cdr L) (car L)) (uniquelist (cdr L)))
(else (cons (car L) (uniquelist (cdr L))))
))
So..
(uniquelist '(1 1 2 3)) => (1 2 3)
...but...
(uniquelist '(1 2 3 1)) => (2 3 1)
Is there a simple alternative that maintains the order of the first instance of each duplicate?
The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:
(define (uniquelist L)
(let loop ([lst (reverse L)] [acc empty])
(cond [(empty? lst)
acc]
[(member (first lst) (rest lst))
(loop (rest lst) acc)]
[else
(loop (rest lst) (cons (first lst) acc))])))
Or we can write the same procedure using standard Scheme, as shown in SICP:
(define (uniquelist L)
(let loop ((lst (reverse L)) (acc '()))
(cond ((null? lst)
acc)
((member (car lst) (cdr lst))
(loop (cdr lst) acc))
(else
(loop (cdr lst) (cons (car lst) acc))))))
The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:
(uniquelist '(1 1 2 3))
=> '(1 2 3)
(uniquelist '(1 2 3 1))
=> '(1 2 3)

Resources