Scheme object is not applicable - 2 different ways - scheme

I am writing some code for a roster management program in scheme, but encounter an issue when I try to add a student. I am using a roster parameter which is a list of lists, each sublist being a student's record. The first student I add works without issue, however when I attempt to add a second student, I receive one of two instances of the same error.
If I try to enter a student who should be added, I get the error :
The object ("21" "Anon Ymous" "89") is not applicable.
If the student I add has information that conflicts with the existing student, I get the error :
The object (("23" "Anon Ymous" "11")) is not applicable.
The code for this section is as follows :
(define addifnotcontains
(lambda (roster item)
(cond ((null? roster) (list item))
((equal? (car (car roster)) (car item))
(begin
(display "\tID Already Exists\n")
(roster)
))
((equal? (cadr (car roster)) (cadr item))
(begin
(display "\tName Already Exists\n")
(roster)
))
(else (cons ((car roster) addifnotcontains (cdr roster))))
)
)
)
and the call for this function is (menu (addifnotcontains roster (buildobject 0 '()))) where menu is a lambda function that simply takes in a roster
I know that this issue has been caused by mismatched or misplaced parentheses in my code previously, but I cannot tell why it is occurring this time. I suspect it has something to do with calling (roster) at the end of the begin block, but as I understand it, the begin block returns the last value called within the block. What am I doing wrong?

In the first case, you're trying to apply (car roster) to addifnotcontains and (cdr roster):
(cons ((car roster) addifnotcontains (cdr roster)))
^ <-- This is one expression --> ^
You're also only passing one argument to cons and forgetting to pass along item.
This should be
(cons (car roster) (addifnotcontains (cdr roster) item))
In the second case, you're trying to apply roster as a function.
You're correct in that the value of a begin block is the value of the last expression in the block, but in your case this expression should be roster, not (roster).
(Remember that you can't add parentheses willy-nilly in Scheme like you can in some other languages; parentheses are always significant.)

Related

Scheme - Inserting a number in a List

I have this code :
(define (Insert value list)
(if (null? list) (list value))
(if (< value (car list)) (list (Insert (value list))))
(Insert (cdr list) list))
I want this code to take a list (assuming it's in low to increasing order of integers) and insert a number in the correct place. This code does not work but I don't know why. Anyone know?
You have a bunch of errors. First, let's see how you can fix your implementation:
(define (insert value lst)
(cond ((null? lst) ; if the list is empty
(list value)) ; then return a single-element list
((<= value (car lst)) ; if current element >= value
(cons value lst)) ; insert value in current position
(else ; otherwise keep building the list
(cons (car lst) ; by adding current element
(insert value (cdr lst)))))) ; and advancing recursion
Now, let's see what went wrong with your code:
You must not name a parameter list, that clashes with the built-in procedure of the same name - one you're actually using! it's clear that they'll conflict
The conditionals are incorrectly structured, if you have multiple conditions use a cond expression. Notice that the values of the first two ifs are discarded, because they're not nested (inside a procedure, only the value of the last expression is returned). Some Scheme interpreters will even raise an error when you write ifs without the corresponding else part
In the second condition, you must stop the recursion by consing the value with the rest of the list. It's better to stop as soon as possible, when element >= value, in case there are repeated elements
In the last condition, you're passing the parameters in the wrong order, and forgot about the value
Also in the last condition, you forgot to cons the current element
You have several errors in your code. First, in Scheme it is more natural to include else clauses for ifs. Also, you had wrong the last if. Here is a version of your code with minor modifications:
(define (Insert value lst)
(if (null? lst) (list value)
(if (< value (car lst))
(cons value lst)
(cons (car lst) (Insert value (cdr lst))))))
Note that you have to provide actions for when the value is less than the head of the list and when it is not, and you have to construct the returning value using cons.

Using Scheme to assign the value returned by a function to a variable in another function

I have a function remove_duplicates that removes the duplicates in a list and returns the new list.
(define (remove_duplicate list)
(cond
((null? list) '() )
;member? returns #t if the element is in the list and #f otherwise
((member? (car list) (cdr list)) (remove_duplicate(cdr list)))
(else (cons (car list) (remove_duplicate (cdr list))))
))
I want to assign the return value from this function call to a variable in another function f.
(define (f list)
;I have tried this syntax and various other things without getting the results I would like
(let* (list) (remove_duplicates list))
)
Any help is appreciated, thanks!
This is the correct syntax for using let:
(define (f lst)
(let ((list-without-dups (remove_duplicates lst)))
; here you can use the variable called list-without-dups
))
Also notice that it's a bad idea to name list a parameter and/or a variable, that clashes with a built-in procedure with the same name.

How do I find the number of lower case letters in Scheme Racket?

I'm trying to find the number of lower/upper case letters in a string, but there is a problem with my code:
(define case
(lambda (list)
(if(char-lower-case? (car list))
(case (cdr list))
(+ 1 (case (cdr list)))
)
))
(case (string->list "ScheMe"))
How can I solve this problem?
In your function you have two problems:
case is a predefined operator in racket/scheme
You don't test for an empty list.
Moreover, you use the parameter list, which is a primitive operator and should not be used as variable name.
Here is a working function:
(define (case1 lst)
(cond ((null? lst) 0)
((char-lower-case? (car lst)) (case1 (cdr lst)))
(else (+ 1 (case1 (cdr lst))))))
(case1 (string->list "ScheMe"))
Your code lacks a base case. (case '()) should evaluate to 0 but you get an error since you are doing car and cdr on nil.
Other things that might be wrong:
Your title indicates that you want to count lowercase letters but you increase for every uppercase.
list and case are names from the standard library. For R5RS it means undefined behaviour and for R6RS and later it means the library bindings would be unavailable. In #!racket (I guess you use this language since you tagged racket) it works as R6RS.

Scheme getting last element in list

Im trying to write a simple scheme function that returns the last element of a list. My function looks like it should work, but I managed to fail on something:
(define (last_element l)(
(cond (null? (cdr l)) (car l))
(last_element (cdr l))
))
(last_element '(1 2 3)) should return 3
DrRacket keeps on giving me the errors:
mcdr: contract violation
expected: mpair?
given: ()
Since (null? '()) is true, I don't get why this doesn't work.
This is a function I think I will need for a homework assignment (writing the function last-element is not the assignment), and the instructions say that I cannot use the built-in function reverse, so I can't just do (car (reverse l))
How do I fix this function?
Your syntax is totally wrong. You have an extra set of parentheses around the body of the function, not enough around the cond clauses, and your recursive case isn't even within the cond, so it gets done whether the test succeeds or fails. The following procedure should work:
(define (last_element l)
(cond ((null? (cdr l)) (car l))
(else (last_element (cdr l)))))
Just to add: in professional-level Racket, the last function is a part of the racket/list library.
you can retrieve the last element of a list by calling
(define (lastElem list) (car (reverse list)))
or, recursively using if built-in
(define (last list)
(if (zero? (length (cdr list)))
(car list)
(last (cdr list))))
You can also do it like this.First find the lenght of a list by cdring it down.Then use list-ref x which gives the x element of the list.
For example list-ref yourlistsname 0 gives the first element (basically car of the list.)And (list-ref
yourlistsname (- length 1)) gives the last element of the list.

the difference between if and cond?

i'm learning sicp now and do the ex2.23
i have wrirten the following code:
(define (for-each proc items)
(if (null? items)
#t
((proc (car items))
(for-each proc (cdr items)))))
but when running, cause error: procedure application: expected procedure, given: #; arguments were: ()
i think i know the reason: I call the for-each function recursively, every called for-each wanted to return value
but when i have modified the code:
(define (for-each proc items)
(cond ((null? items) #t)
(else (proc (car items)) (for-each proc (cdr items)))))
it runs well. I don't understand, why? in cond, does every called for-each no need to return value?
i used DrScheme, and choose language SICP
i'm not a native speaker of english, so if there is sth which isn't described clearly, pls tell me
but when running, cause error: procedure application: expected > procedure, given: #; arguments were: ()
i think i know the reason: I call the for-each function recursively, > every called for-each wanted to return value
No, it is because in the alternative clause of if you have the combination ((proc (car items)) (for-each proc (cdr items))). You intended to evaluate the two combinations (proc (car items)) and (for-each proc (cdr items)) sequentially, and to that end you thought putting them in another pair of parentheses would work. But in actuality, what you have specified is that the result of (proc (car items)) is a procedure to be applied to the argument which is the return value of (for-each proc (cdr items)). This is not the case, and you get an error. The key point being that parentheses in Lisp are not for grouping, but have a definite significance.
The problem is that if can only have a single combination in that position, whereas you want to have two in a row. On the other hand, cond does not suffer such a restriction; you can put as long a sequence of individual combinations in the consequent part of a cond clause as your heart desires. This state of affairs is simply how the language is defined to work.
You can just as well use cond in these situations, but if you still want to use if there are some options for stuffing multiple combinations into one. E. g. you can create a lambda procedure whose body is the two combinations and immediately fire it off:
(define (for-each proc items)
(if (null? items)
#t
((lambda ()
(proc (car items))
(for-each proc (cdr items)) )) ))
Or you can use begin which is actually meant to be used for such a purpose:
(define (for-each proc items)
(if (null? items)
#t
(begin
(proc (car items))
(for-each proc (cdr items)) ) ))

Resources