Racket Contract Violation (Max Recursion Function) - scheme

Learning some Scheme/Racket, so give me some leeway.
Currently trying to find the max value when given a list without using the built-in max() function.
Current Code:
#lang racket
(provide max-num)
(define (max-num lst)
(define (helper lst max)
(displayln lst)
(displayln max)
(displayln " ")
(when (null? max) ; first run
(helper (cdr lst) (car lst)))
(if (null? lst)
max ; then end
(if (> (car lst) max) ; else compare
(helper (cdr lst) (car lst)) ; then update max
(helper (cdr lst) max)))) ; else keep max
(if (null? lst)
#f ; then Error
(helper lst '())) ; else run helper
)
(max-num '())
(max-num '(1 5 2 4 3))
Output via DrRacket:
As far as I can tell, the displayln outputs tell me I am on the right track. However, it ends up with a contract violation real? error instead of returning the max value.
I'm guessing that the (if (null? lst)) doesn't want to return "max" at the end and instead pushes towards the else branch despite the list being empty. I've looked around and debugged for about an hour now to no avail. Any help would be greatly appreciated.

You have to know that when you do:
(when test
do-something)
do-something-else
It will always do-something-else regardless if test is true or not. SO what is happening is that the first round max is null? and it does (helper (cdr lst) (car lst))) and that returns the answer. Then it discard that answer and continue to the if with max being null? and it finally fails when it does (> (car lst) max) since a null? is not a number. The error message says it expected a real? but it got the initial value '().
So to hint you on your way you should have one expression in addition to the local definitions eg.
(if test1
result1
(if test2
result2
alternative2))
or
(cond (test1 result1)
(test2 result2)
(else alternative2))
And of course since you know the argument is not null? you could just call (helper (cdr lst) (car lst)) instead of passing the empty list and remove the when entirely. when and unless are for side effects and not really for good functional Scheme style.

Related

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

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

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.

Function count should accept two arguments: an atom and a simple list. The function should return the number of times the atom is found in the list

I am new to scheme and have been given this problem as homework. I don't know how to keep a running count in scheme, and that's the part I need help with.
Here's the problem again:
Function count should accept two arguments: an atom and a simple list. The function should return the number of times the atom is found in the list.
Here's what I have so far:
(define (count atm lst)
(cond
((null? lst) 0)
((eq? atm (car lst)) (i don't know how to make a count) (count atm (cdr lst)))
(else (count atm (cdr lst)))))
Any help would be very appreciated!
I still don't understand what needs to happen to increment the number of times the atom is found in the list for each iteration of the function.
This is the test case my teacher gave me:
(count 'john '(john paul george ringo))
which should return 2.
I've been staring at this problem long enough, please explain how to make the count work.
You, my friend, are very very close to the answer to this problem. To finish the problem, you need to write a test case. The reason you need to write a test case is that you can then think concretely about what the pieces of your code mean. Most specifically, you need to think about what (count atm (cdr lst)) evaluates to for the particular input that you're thinking of, and then think about what the correct answer is, and how they're related.
Let's look at your code.
(define (count atm lst)
(cond
;; This is obviously correct
((null? lst) 0)
;; See below
((eq? atm (car lst)) (somefunction (count atm (cdr lst))))
;; The next one's find as well
(else (count atm (cdr lst)))))
If the tail (cdr) of lst contains n occurrences of atm, (count atm (cdr lst)) should return n. Then, knowing n, if (car lst) is eq? to atm, how many are there in lst?
(define (count-atom atm list)
(cond((null? list) 0)
((eq? atm (car list)) (+ 1 (count-atom atm (cdr list))))
(else (count-atom atm (cdr list)))
)
)
(count-atom 'a '(a b a b a r a a a a a a a a a))

How to count the number of zeros in a list?

I'm new to Scheme, so can anyone give me an example? There's no local variable in Scheme, so how can I keep track of the number of zeros that being encountered.
I tried
#lang scheme
(define zeroes
(lambda (ll)
(cond ((null? ll)
0)
(else (= 0 (car ll))))
(zeroes (cdr ll))
)
)
But the compiler complained:
cdr: expects argument of type <pair>; given ()
Thanks,
Here's my solution (since the OP's already posted theirs):
(define (count-zeroes lst)
(let loop ((lst lst)
(count 0))
(cond ((null? lst) count)
((zero? (car lst)) (loop (cdr lst) (+ count 1)))
(else (loop (cdr lst) count)))))
Of course, no treatment of this subject can be considered complete without talking about fold, which is usually used to "summarise" a list down to a single object (like we're doing for this question):
(define (count-zeroes lst)
(fold (lambda (elem count)
(if (zero? elem) (+ count 1) count))
0 lst))
Just figured out the solution,
(define count
(lambda (lst)
(cond ((null? lst) 0)
((= 0 (car lst)) (+ 1 (count (cdr lst))))
(else (+ 0 (count (cdr lst))))
)
)
)
I'm keeping this at a hint level for now.
Your function is doing two things. First it computes 0 if its argument is an empty list, or #t or #f if its argument is a list that begins with 0 or not. Then it throws that result out and calls itself recursively on the rest of the list.
You're going to have to do two things to make this work: 1) combine the results of the individual zero tests somehow (for a thought experiment, look at your code; how would it ever return the value 2 if the list had two zeroes?); 2) "bottom out" successfully when it calls itself recursively on an empty list.

Resources