Adding arguments to list causes error - scheme

I tried an example where we need to pass a list as arguments and if condition succeeds I want to add result to a new list.
Here's the code:
(define get-description
(lambda (codeValue newList)
(cond
((= (car codeValue) 1) (cons "A" newlist))
((= (car codeValue) 2)(cons "B" newlist))
((= (car codeValue) 3) "C")
(else "Negative numbers are not valid"))))
I pass this as the function call:
(get-description (list 1 2 3) (list))
I get output:
(cons "A" empty)
Output should just show: (A)
I am using DrRacket for writing my programs and have chosen language mode as: Beginning Student.
Why do I get cons and A with "" and empty in my newlist?

Please don't use "Beginning Student" as a language type in Racket. That's a subset specially made for the HtDP book. The languages "racket", "r5rs", "pretty big", are more like real Schemes and should all work for The Little Schemer.
In your arguments list, you have (codeValue newList), but in the program body you refer to newlist. All of the Schemes that I've used are case-sensitive. Changing your newList to newlist made your program run perfectly fine on Chez Scheme and Guile too.
Edit: To clarify, "A" is a string. Scheme also has the additional data type of symbol, which is just a name and nothing else (and is probably what you want here). You probably want to (cons 'A newlist) rather than (cons "A" newlist) if you're expecting (A).

Other Schemes would print just ("A"). Such output is clearly an idiosyncrasy of the Racket language.
As for why the A is in quotation marks, that's because it's a string object, and that's simply how string objects are printed. But if you were to DISPLAY such an object, you'd get the A by its lonesome.

Related

Scheme: how to get first atom from list

I need help with one issue: I can't handle how to get the first atom from the list in SCHEME language. I think I should make a loop, something like "while" and compare each element on boolean (?atom) and print first matched item.
Unfortunately, It's difficult for me to handle scheme syntax.
Please, can you propose any solution for me?
define func ?atom:
(define (atom? x) (not (or (pair? x) (null? x))))
Recursion is not that different from the usual way yo solve problems - you just have to be careful and set some meaningful base cases. For instance, how would you solve this problem in Java? by traversing all the list, and stoping when either 1) we found the element that matches the condition or 2) there are no more elements. This is exactly what we need to do:
(define (first-atom lst)
(cond ((null? lst) #f) ; there are no more elements in the list
((atom? (car lst)) ; current element is an atom
(car lst)) ; return it
(else ; otherwise
(first-atom (cdr lst))))) ; look in the rest of the list
It works as expected:
(first-atom '((2) 42 (3)))
=> 42
(first-atom '((1) (2)(3)))
=> #f
In your question you have the definition to atom? that returns #t if the argument is an atom and #f otherwise.
The function should handle the empty list. eg. What should happen when you do this:
(first-atom '())
Thus you need to check if the argument is the empty list and return whatever you supposed to return when there are no atoms in the arguments. Then you'll have a else expression that handles the rest.
You can use first to get the first element to check if it is an atom and then return it or you recure with the rest of the list.
Now here is something very similar that finds the number of elements in a list:
(define (length lst)
(if (null? lst)
0 ; obviously a 0 length list
(+ 1 (length (cdr lst))))) ; obviously one plus whatever length the rest is
Imagine what happens if you do (length '(1 2)). It does (+ 1 (length '(2))) which again does (+ 1 (+ 1 (length '()))) which again does (+ 1 (+ 1 0)). Simple as that. All loops are recursive functions in Scheme.
You reference to while indicates you might be familiar with other programming languages. I knew C, C++, Pascal, perl, PHP, and Java when starting to learn Lisp and I suddenly realized all the languages I knew were only subtle dialects of one language, Algol. I wasn't learning my sixth language, but my second. Scheme doesn't have a while loop. It has recursion. you need to get a book and start at the first page as if you didn't know how to program at all as assimilation from Algol will point you in the wrong direction.

Can someone explain equality to me in scheme/racket?

So I stumbled across this today and it has me puzzled.
(define (x) '(1))
(eq? (x) (x)) ;=> #t
(eq? '(1) '(1)) ;=> #f
(define (y) (list 1))
(eq? (y) (y)) ;=> #f
(eq? (list 1) (list 1)) ;=> #f
Can anyone explain what's happening here ?
When compiled this program
(define (x) '(1))
(eq? (x) (x))
(eq? '(1) '(1))
is compiled into (something like):
(define datum1 '(1))
(define datum2 '(1))
(define datum3 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum2 datum3)
Therefore (x) will always return the object stored in datum1.
The expressions (eq? '(1) '(1)) on the other hand will
find out that datum2 and datum3 does not store the same object.
Note: There is a choice for the compiler writer. Many Scheme implementation will compile the above program to:
(define datum1 '(1))
(define (x) datum1)
(eq? (x) (x))
(eq? datum1 datum1)
and then the result will be true in both cases.
Note: The documentation of quote doesn't explicitly state whether multiple occurrences of '(1) in a program will produce the same value or not. Therefore this behavior might change in the future. [Although I believe the current behavior is a deliberate choice]
eq? checks if the objects are the same (think "if the pointer refers to the same address in memory").
In the first case you're working with literals created at compile time. Comparing (and modifying) literals is generally undefined behaviour. Here it looks like procedure x returns the same literal every time, but in the second expression it looks like the 2 literals are not the same. As I said, undefined behaviour.
In the second case you're not working with literals but list creates a new list at execution time. So each call to y or list creates a fresh list.
uselpa's answer is correct.† I wanted to expand on what a quoted datum is, a little further, though.
As you know, all Scheme programs are internally read in as a syntax tree. In Racket, in particular, you use the read-syntax procedure to do it:
> (define stx (with-input-from-string "(foo bar)" read-syntax))
> stx
#<syntax::1 (foo bar)>
You can convert a syntax tree to a datum using syntax->datum:
> (syntax->datum stx)
'(foo bar)
quote is a special form, and what it does is return the quoted portion of the syntax tree as a datum. This is why, for many Scheme implementations, your x procedure returns the same object each time: it's returning the same portion of the syntax tree as a datum. (This is an implementation detail, and Scheme implementations are not required to have this behaviour, but it helps explain why you see what you see.)
And as uselpa's answer says, list creates a fresh list each time, if the list is non-empty. That's why the result of two separate non-empty invocations of list will always be distinct when compared with eq?.
(In Scheme, the empty list is required to be represented as a singleton object. So (eq? '() '()) is guaranteed to be true, as is (eq? (list) '()), (eq? (cdr (list 'foo)) (list)), etc.)
† I would not use the phrasing "undefined behaviour" for comparing literals because that's easily confused with the C and C++ meaning of UB, which is nasal demons, and although the result of comparing literals may not be what you expect, it would not cause your program to crash, etc. Modifying literals is nasal demons, of course.

Append list from assoc to another list in Scheme

I'm a bit confused on how to append a list that I've gotten from the assoc procedure into another list, here is what I have:
(define new-list (list 'test))
(define source-a (list '(a foo) '(b bar) '(c hello)))
(append new-list (assoc 'a source-a))
(display new-list)
The output is just (test) and I'm not sure why it's not (test a foo). Is it possible to append like this?
That's because append is not a mutating function. It returns a new list with its arguments appended together. By convention in Scheme, functions that perform mutation end with an exclamation mark, such as set!.
You can use set! to modify new-list so that it is updated, like this:
(set! new-list (append new-list (assoc 'a source-a)))
However, this is highly discouraged in Scheme. While imperative programming makes heavy use of mutation, functional programming languages (including Scheme) try to avoid mutation and side-effects, since those can make programs harder to reason about.
Ideally, you'd just declare a new binding with the new value instead of updating an existing binding. Something like this would work just fine:
(define original-list (list 'test))
(define source-a (list '(a foo) '(b bar) '(c hello)))
(define new-list (append original-list (assoc 'a source-a)))
(display new-list)

Procedure printf in Scheme

For example, when I use the procedure printf on the list '((2 t r d)), the last line in my output is
'(#<void>)
and the number of times '(#<void>) appears depend on the number of list nested. Can you please explain this for me???
This is my printf function
(define counting
(lambda (lst)
(if (null? lst)
'()
(printf "~a, ~s\n" (car lst) (length (cdr lst))))))
I have try to other procedure like fprintf and using this form
(fprintf (current-output-port) "~a, ~s\n" (car lst) (length (cdr lst)))
Same thing happens!
AFAIK there is no such procedure in the Scheme standard so you might need to add a tag for a implementation that has it. I know racket has printf.
A (display x) (and (printf x) in racket) alone usually don't display so what produced (#<void>) is not in the question. In Scheme every procedure evaluates to a value. To illustrate this try doing:
(map display '(1 2 3 4))
Which will return a list with 4 unspecified values since map makes a list of the results. display (and printf in racket) prints the result of the evaluation of the argument but doesn't need to return anything since the standard doesn't say that is should. Most implementations do this by returning an undefined object, but some actually return the argument too. The main function of them is to do side effect of displaying something on screen and that it has done. for ignoring return values you can use for-each which is map just for side effects.
(for-each display '(1 2 3 4))
When that said in Scheme it's normal that every procedure return something and you misread output with the REPLs printing of the returned values.
You said that 'the last line of your output is '(#<void>) - this is occurring because your Scheme environment is displaying 1) what you want to be printed and 2) the returned value of the evaluated expression. For example
> (list (display 1))
1(#<void>)
The '1' is printed and then the list result is printed. Since you are typing in an interactive session you will always get the returned value displayed. You can't really hide the returned value however most Schemes will recognize a 'undefined' return value and not print it.
> (display 1)
1
In the above, even though display returns #<void> the interpreter knows not to show it.

empty list without empty word in Scheme

I am writing a recursion function returning an empty list in the base case. However the output of functions shows "empty" word in the my list, which I don't want.Like this;
(list (list 'abc) (list 'def) empty (list 'ghi))
How can I prevent this? Thanks.
The problem is probably because Racket has several printing styles for values. Try changing it (in the language selection dialog) to "write" or whatever it's called, which should make it output ((abc) (def) () (ghi)) instead.
The empty that you see in the result is not a "word" -- note that it's not quoted. If you do expect an empty list in the result, then it looks like you got one. You can even check for that:
> (empty? (third (list (list 'abc) (list 'def) empty (list 'ghi))))
#t
Without knowing details, my best guess would be something like
(let ((result (recursive-call ...)))
(if (null? result) (resursive-call (cdr whatever-list))
(cons result (cdr whatever-list)))
Essentially, just check if the result is the empty list, and if so, don't put it into the list that you're returning.

Resources