What is wrong with scheme code? - scheme

i am trying to write a scheme program which will take a list of marks as input and gives the output as a list of the grades.
i got this far , .. i dunno whats wrong i get an error the object () passed as the first argument to cdr is not the correct type ....
here is the code
(define (grades list1)
(cons (cond ((= (car list1) 100) 'S)
((= (car list1) 90) 'A))
(cons (grades (cdr list1)) '())))

You're missing a base case for your recursion. How do you want your grades function to behave when the argument is an empty list? This requires an outer cond that tests is the list is empty and returns something appropriate when it is.

(define (grades list1)
(cond((null? list1) `())
(else(cons (cond ((= (car list1) 100) 'S)
((= (car list1) 90) 'A))
(grades (cdr list1))))))

Related

How to find the mean of a list with mixed symbols (numbers and characters) in scheme?

Given a list of the type '('a 1 'b 2 'c 3) I want to calculate the mean of the numbers in the list.
This is what I have done so far: I have written 3 functions that work correctly, one to remove the characters, the other to calculate the sum of the numbers in a list, and the other to find the average. But I do not know how to put them together to solve my problem.
;remove all non numbers from a list:
(define (all-numbers x)
(cond ((null? x) null)
((integer? (car x)) (cons (car x) (all-numbers (cdr x))))
(else (all-numbers (cdr x)))))
;sum the elements of the list
(define (sumlist lst)
(cond ((null? lst) 0)
(( + (car lst) (sumlist (cdr lst))))))
; find the mean of the list
(define (a_mean lst)
(cond ((null? lst) 0)
((/ (sumlist lst) (length lst)))))
(a_mean '(1 2 3))
;find the mean of a mixed list
(define (m_mean lst)
(cond ((null? lst) 0)
((/ (sumlist ((all-numbers lst)) (length (all-numbers lst)))))))
(m_mean '('a 1 'b 2 'c 3))
I get an error in the above code for m_mean. Please help! Thanks.
The answer by Óscar López should fix your problems.
I will now provide a more concise way of solving the same problem:
(define (m-mean lst)
(define all-numbers (filter number? lst)) ; Filter out all the non-numbers.
(if (null? all-numbers)
0 ; The mean is 0 if there are no numbers.
(/ (apply + all-numbers) (length all-numbers)))) ; Calculate mean.
This way, you do not have to explicitly define the all-numbers and sumlist functions.
For starters, some of your cond expressions are missing the else keyword in the final condition - this is mandatory, as you did in all-numbers. Also, in m_mean there are a couple of incorrect brackets; this should fix the errors:
(define (m_mean lst)
(cond ((null? lst) 0)
(else (/ (sumlist (all-numbers lst))
(length (all-numbers lst))))))
Now it works as expected:
(m_mean '(a 1 b 2 c 3))
=> 2

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 add an element into a specific position of a list, using Scheme?

This is the code I have so far. I believe that I'm close, but what returns is just #procedure, acknowledging that a procedure has created, it does not return the list with the newly added element. I have been working on this for hours and I am at a loss of where I have gone wrong.
(define (add-into new p lst)
(cond ((null? lst)
(cons new lst)
((eq? p 0)
(cons new lst)
(else
(cons (car lst) (add-into (- p 1) new (cdr l))))))))
You have parentheses problems, in one place you passed l instead of lst and the order of the parameters is incorrect when doing the recursive call. This should fix the errors:
(define (add-into new p lst)
(cond ((null? lst)
(cons new lst))
((= p 0)
(cons new lst))
(else
(cons (car lst) (add-into new (- p 1) (cdr lst))))))
Just pasting the code into DrRacket and pressing CTRL+i and I get this:
(define (add-into new p lst)
(cond ((null? lst)
(cons new lst)
((eq? p 0)
(cons new lst)
(else
(cons (car lst) (add-into (- p 1) new (cdr l))))))))
Notice that you only have one term. If (null? lst) is #f there are no more terms in the cond so it will evaluate to a implementation defined value as it is it is undefined in the specification. In #lang racket that value is the same as returned if you evaluate (void)
To fix it you need to close the terms in the cond so that you have 3 terms instead of one. You should have seen this when you press enter that the parentheses didn't align to the previous term. If you want to use another editor you should get one that aligns and indent lisp syntax as writing lisp without is slightly painful.

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.

Combining count and flatten functions in scheme

So i have these two functions that work fine alone. I am trying to write one function to accomplish both but i keep getting a car error. Any guidance on the best way to solve this?
(define (countNumbers lst)
(cond
((null? lst) 0)
((number? (car lst))(+ 1 (countNumbers (cdr lst))))
(else (countNumbers (cdr lst)))))
(define (flatten x)
(cond ((null? x) '())
((pair? x) (append (flatten (car x)) (flatten (cdr x))))
(else (list x))))
I tried something like this im rather new to functional programming in general so im still trying to wrap my mind around it it says the problem is after number?(car lst)
(define (flatten lst)
(cond ((null? lst) '())
((pair? lst) (append (flatten (car lst)) (flatten (cdr lst))))
(else (list(cond
((null? lst) 0)
((number? (car lst))(+ 1 (flatten (cdr lst))))
(else (flatten (cdr lst))))))))
As I mentioned in my comment, I don't think it's a good idea to stick everything in a single function. Anyway, you were kinda on the right track, but we have to remember that if we're going to return a number as the final result, then our base case should reflect this and also return a number (not an empty list), and the combining step should add numbers, not append them. This is what I mean:
(define (count-flatten lst)
(cond ((null? lst) 0)
((pair? lst)
(+ (count-flatten (car lst))
(count-flatten (cdr lst))))
((number? lst) 1)
(else 0)))
But I'd rather do this:
(define (count-flatten lst)
(countNumbers (flatten lst)))
We can even write an idiomatic solution using only built-in procedures, check your interpreter's documentation, but in Racket we can do this:
(define (count-flatten lst)
(count number? (flatten lst)))
Anyway, it works as expected:
(count-flatten '(1 x (x 2) x (3 (4 x (5) 6) 7)))
=> 7

Resources