Is there anything wrong with my "sum of list" code in scheme? - 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

Related

How to create a function that receives a list and creates a new list in 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)))

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.

Sum of all numbers in a list at the top level

I'm new to Scheme and I've spent about a week on this.
Write a Lisp function sumlist which takes a list and returns the sum of all the numbers in the list, at the top level. Thus,
(sumlist '(1 2 (3) (4 a) nil b 5)) should return 1+2+5=8. The numbers 3 and 4 are not at the top level. Use number? to check if a thing is a number."
This is what I have so far. It can recognize whether something is a number or not, but I can't get it to only add up the numbers on the top level.
(define (sumlist lst)
(cond ((null? lst) 0)
((number? lst) lst)
((list? lst)
(+ (sumlist (car lst)) (sumlist (cdr lst))))
(#t 0)))
; no values returned
> (sumlist '(1 2 (3) (4 a) nil b 5))
15
Any help is appreciated.
EDIT: Both Jedi's and Daniel's answers work. Thank you both very much.
I think it can be a bit simpler:
(define (sumlist lst)
(cond
((null? lst) 0)
((number? (car lst)) (+ (car lst) (sumlist (cdr lst))))
(else (sumlist (cdr lst)))))
Since you only care if an element is a number or not, you only have 3 cases.
(define (sumlist lst)
(cond ((null? lst) 0) ;; list is empty, we're done ;;
((number? (car lst)) (+ (car lst) (sumlist (cdr lst)))) ;; the first item is a number, so we add it to the rest
(else (sumlist (cdr lst))) ;; the first item was not a number, we just check the rest of the list
))

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

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

Resources