How do I write an if-else statement in Scheme? - functional-programming

I would like to convert these double if statenments into an if-else statement.
(if (symbol? x)
(begin
(display "ONE")
)
)
(if (integer? x)
(begin
(display "TWO")
)
)
Without using racket.

Using only standard Scheme, we have cond for this:
(cond ((symbol? x) (display "ONE"))
((integer? x) (display "TWO"))
(else (display "OTHER")))
If you have some sort of restriction and you must use if, we can nest it:
(if (symbol? x)
(display "ONE")
(if (integer? x)
(display "TWO")
(display "OTHER")))
We can remove the begin expressions. In the cond version they’re completely unnecessary, and in the nestedif version they’re not required when there’s a single expression inside.
In both versions I added an else condition because some Scheme flavors make it mandatory and anyway is a best practice.

Related

Using symbol parameters in a function without parentheses and quote in Common Lisp

(defun all-longer-than-1-char? (&rest elements)
(every (lambda (x) (> (length
(cond ( (typep x 'integer) (write-to-string x) )
( (typep x 'string) x )
( (typep x 'symbol) (symbol-name x) )
))
1))
elements))
(all-longer-than-1-char? "OK" "NO" 1)
I'd like this function to work on symbol parameters (i.e. without having to double quote or to enter numbers) but it doesn't work. To make it work with symbol parameters:
(defun all-longer-than-1-char? (lst)
(every (lambda (x) (> (length
(cond ( (typep x 'integer) (write-to-string x) )
( (typep x 'string) x )
( (typep x 'symbol) (symbol-name x) )
))
1))
lst))
(all-longer-than-1-char? '(OK NO 1))
NIL
But this time I have to enclose the parameters inside parentheses and quote it. I'd like to make it work both with symbol parameters and without having to put parameters inside parentheses and quote them, like:
(all-longer-than-1-char? OK NO 1)
How to do it?
You can use &rest to create what would once have been called a 'nospread' function (or an 'lexpr' depending on your religion), which is very often less useful other than as a user-interface since if you have a list of things you then have to use apply.
Common Lisp doesn't have functions which don't evaluate their arguments, which was once what was known as a 'nlambda' (or an 'fexpr' if you belong to the wrong cult), so you need to quote forms which would otherwise mean something to the evaluator.
You can get the same result as an nlambda with a macro. But you almost certainly don't want to do that as it smells like a bad use of a macro.
Given
(defun all-longer-than-1-char-p (list)
(every (lambda (x)
(> (length
(etypecase x
(string x)
(integer (write-to-string x))
(symbol (symbol-name x))))
1))
list))
Then the nospread one might be
(defun all-longer-than-1-char-p/nospread (&rest list)
(all-longer-than-1-char list))
And the nlambda one might be
(defmacro all-longer-than-1-char-p/quoted/nospread (&rest things)
`(all-longer-than-1-char ',things))
So now
> (all-longer-than-1-char-p '(xx yy 12 "foo"))
t
> (all-longer-than-1-char-p/nospread 'xx 'yy 12 "foo")
t
> (all-longer-than-1-char-p/quoted/nospread xx yy 12 "foo")
t
(All assuming *print-base* is less than 13).
But
> (let ((x "xx"))
(all-longer-than-1-char-p/quoted/nospread x))
nil
So, not very semantically useful, and kind of a poster child for how not to use macros.

Scheme Trying to check if a word in the list

I have a few functions.
(define adjs '(black brown fast hairy hot quick red slow))
(define adj?
(lambda (a) (if (member a adjs) #t #f)
)
(define OK
(lambda (x)
(cond
((equal? x()) #t)
((equal? adj? (car x)) OK(cdr x))
((else x #f))
)
)
)
The function adj? is checking to see if the input is part of the list of adjectives in adjs.
What I am trying to do with the OK function is the user will input a list and have that list run through adj? to see if it is part of the adjs list.
What happens when I run the function is I get an error return that says I entered in "X" amount of arguments when the function only expected two. Why?
There are problems with the parentheses. Some are unnecessary and others are missing, for example when you recursively call the OK procedure, or in the way you're calling adj? - remember, in Scheme we call a procedure like this: (f x), not like this: f(x). Also, the base case of the recursion seems off, and the else clause is used incorrectly. Try this:
(define adj?
(lambda (a)
(if (member a adjs) #t #f)))
(define OK
(lambda (x)
(cond
((null? x) #t)
((adj? (car x)) (OK (cdr x)))
(else #f))))

Scheme Recursion Loop Incorrect Values and Variable Binding

I started a question here about a hangman game I am working on.
Recursive Scheme Function Value Error
I feel that the hangman portion is confusing people from my real issue and question. My problem is, I call various defined functions from within my recursion loop and get incorrect values. When I call these same function by themselves (not in a recursive loop) they work as expected. I know it is either something I am overlooking or a variable binding issue is going on that I need a workaround for.
First here a reproduction of the problem code:
(define (recurse a_list a_number)
(cond ((= a_number 0)
(display "Zero Condition.")
)
(else
(display "\n\n")
(display-list a_list ",")
(display "\n")
(display (car a_constant))
(display "\n")
(display "If the above letter is in the list, result should be true\n")
(display (contains? a_list (car a_constant)))
(display "\n")
(display "Enter a letter:")
(recurse (cons (symbol->string (read)) a_list) (- a_number 1))
)
)
)
Here are my definitions used inside the recursive loop:
(define (display-list a_list separater)
(if (null? a_list)
(display "")
(begin
(display (car a_list))
(if (null? (cdr a_list))
(display "")
(display separater))
(display-list (cdr a_list) separater)
)
)
)
(define (contains? list item)
;(display "\n")
;(display list)
;(display "\n")
;(display item)
;(display "\n")
(cond ((empty? list)
#f
)
((eq? (first list) item)
#t
)
(else
(contains? (rest list) item)
)
)
)
(define a_constant '("n" "o" "t" "w" "o" "r" "k" "i" "n" "g"))
(define test_li_1 '("n" "b"))
(define test_li_2 '("a" "b"))
This is what I ran:
> (contains? a_constant (car test_li_1))
#t
> (contains? a_constant (car test_li_2))
#f
It works as expected.
When I run the recursive Loop this is what I get:
> (recurse test_li_2 2)
a,b
n
If the above letter is in the list, result should be true
#f
Enter a letter:n
n,a,b
n
If the above letter is in the list, result should be true
#f
In my mind, the first output is correct, but the second one is not.
When I run with test_li_1 it always evaluates to true which, it should since 'n' is always in my a_list. What I have put together through several tests, is the recursive function keeps using my initially passed in list and does not use the appended version for function calls, which is not what I want it to do. I also think that is not how it should work right? Shouldn't my passed in value be used and not a value from several recursive levels up? I'm testing this all in Dr. Racket with #lang racket in case that matters.
The problem reported occurs because you're using eq? to test for string equality. From the documentation:
(eq? v1 v2) → boolean? : Return #t if v1 and v2 refer to the same object, #f otherwise.
So you see, eq? is testing for identity, not for equality. For that, you should use string=? or equal?. Modify the contains? procedure as follows, and it'll work:
(define (contains? list item)
(cond
((empty? list) #f)
((string=? (first list) item) #t)
(else (contains? (rest list) item))))
When you call (symbol->string (read)) and enter in a, you get a fresh string "a". This is a new string object that is not eq? to any "a" in your program. Try this to see the problem:
(eq? (symbol->string (read)) "a")
If you enter in a, this will output #f because the two string items are separate objects. You've run afoul of string interning. All instances of "a" written in your source code are stored as references to one object upon compilation, so (eq? "a" "a") will evaluate to true. When you (read) input as strings, those strings will be freshly created objects and won't be equal to any other strings. There are two ways you can fix this:
Use string=? for comparison instead of eq? (as in Oscar's answer)
Use lists of characters instead of lists of single-character strings, e.g. '(#\a #\b #\c) is the string "abc". From the Racket documentation of characters:
Two characters are eqv? if they correspond to the same scalar value. For each scalar value less than 256, character values that are eqv? are also eq?
Letter characters (a-z and A-Z) have values less than this in Racket's Unicode encoding, so any letter characters you read in will not run afoul of the eq? issue. This brings up another point - you should be sanitizing your input from read. The read procedure is not guaranteed to return a string, in particular if I enter in 1 instead of a string, it returns the number 1, not the string "1". You should add some logic to handle bad input, or this will crash your program.

Trouble returning recursively-built lists to calling functions in Lisp

I am new to Lisp and have an issue regarding recursion and function returns. In the interests of trying to better understand and solve my problem, I provide the following scenario. I apologize if it is verbose. If this aggravates others, I'm happy to trim it down. To skip right to the business, please read from the horizontal line onward.
Imagine a waitress at a bar. Instead of taking drink orders, she forces her patrons to identify themselves as drinkers of beer, rum, whiskey, or some combination of these. Then she grabs a tray full of either beer, rum or whiskey and does a lap around the bar, leaving exactly one drink with any customer who has identified themself as a drinker of that particular beverage. When she's finished each round, she always sits down and has a Long Island Ice Tea. Afterward, she proceeds to grab another tray of exclusively one type of drink and goes out for delivery again. No customer can ever refuse a drink, and no one can change their drink preferences.
Now, Mindy (the waitress) needs a novel way of keeping track of how many drinks of each type she is delivering to each patron. Mindy isn't very good at math and by the end of the night all of those Long Island Ice Teas are really adding up.
So when she asked for a simple solution for tracking her drink dispensing, I naturally suggested creating a simple little Lisp program. Here's how it is to work: When she has finished delivering a round of tasty beverages, Mindy simply walks up to her Altair 8800 and types the following:
(update-orders <order-list> <drink>)
where is the list of all customers and their orders, and is the drink she just served in her most recent outing.
It should properly go through the lists of customers and their drink counts, updating the proper drinks by one and leaving the others alone. To interface with the computer system in place, a newly-updated orders-list needs to be returned from the function when it is complete.
Just today I came across the following bug: after properly calling the function, the value returned is not what I want. The list only includes the very last drink count list of the very first customer in the list, every time. Recursive programming is the real culprit here, as opposed to Lisp, and I have tried altering the code to fix this, but to no avail. I need a full list returned from the function.
As you may have guessed, this story is not true. The real problem I am trying to solve is related to calculus, and is a well-known topic for those getting their feet wet with Lisp. However, my problem is not with my assignment, but rather with wrapping my mind around the recursive calls and returning full lists of values to calling functions, so that I may build a complete list of all terms to return when finished. After I am able to solve this sub-problem, I am just a stones throw away from applying it to my actual assignment and solving it.
Running the following function call:
(update-orders (quote ( (bill (4 beer) (5 whiskey)) (jim (1 beer)) (kenny (1 whiskey) (4 rum)) (abdul (1 beer) (3 whiskey) (2 rum) ))) (quote beer))
gets me the following returned:
((5 WHISKEY))
I would, instead, like a list in the same format as the one supplied to the function above.
Please see the code below. It has been modified to include debugging output to the screen for convenience. Function drink-list is likely where my trouble lies.
(defun update-orders (x d)
(print 'orders)
(prin1 x)
(order (car x) d)
)
(defun order (x d)
(print 'order)
(prin1 x)
(drink-list (cdr x) d)
)
(defun drink-list (x d)
(print 'drink-list)
(prin1 x)
;(append
;(cons
;(list
(drink-count (car x) d)
(cond
((cdr x) (drink-list (cdr x) d))
(t x)
)
;)
)
(defun drink-count (x d)
(print 'drink-count)
(prin1 x)
(list
(cond
((eq (car (cdr x)) d)
(modify-count (car x) 1))
(t x)
)
)
)
(defun modify-count (x d)
(print 'modify-count)
(prin1 x)
(print 'new-modify-count)
(prin1 (+ (parse-integer (subseq (write-to-string x) 0)) 1))
(list
(+ (parse-integer (subseq (write-to-string x) 0)) 1)
)
)
EDIT:
I have incorporated ooga's suggestions into my code. The new order and update-order functions are shown below:
(defun update-orders (x d)
(cond
((null x) ())
(t (cons (order (car x) d) (update-orders (cdr x) d)))
)
)
(defun order (x d)
;(print 'order)
;(prin1 x)
(drink-list (cdr x) d)
)
I now get the following list returned, running the same function call as above:
(((5 WHISKEY)) ((1 BEER)) ((4 RUM)) ((2 RUM)))
which is a list of embedded lists (2 deep, I believe) that include all of the last drink item and drink count of each patron in the list (Bill's final list entry is 5 whiskey, Jim final entry is 1 beer, etc). Their first n-1 drinks are not added to the returned list of their drinks.
Have I misread your suggestion? I have a feeling I am a half step away here.
In update-orders you only pass the car of x to order. The rest of x is completely ignored. Then you only pass the cdr of that is on to drink-list.
As an example of how your code should be structured, here's a program that adds 1 to each member of the given list.
Example call: (increment-list '(1 2 3))
(defun increment-list (x)
(cond
((null x) ())
(t (cons (increment (car x)) (increment-list (cdr x))))
)
)
(defun increment (x)
(+ x 1)
)
Change increment-list to update-orders and increment to orders (and add the second input, etc.) and that, I think, should be your program structure.
Also, you should try to build it from the bottom up. Try writing a function that will add one to the number if the given drink in a (number drink) list matches. I.e., given this:
(add-one-if '(4 beer) 'beer)
It should return this
(5 BEER)
And given this
(add-one-if '(3 whiskey) 'beer)
It should return this
(3 WHISKEY)
As suggest above, here is the full code I have implemented to solve my problem, incorporating the suggested structure provided by ooga.
;;;; WAITING-TABLES
(defun update-orders (x d)
(cond
((null x) ())
(t (cons (order (car x) d) (update-orders (cdr x) d)))
)
)
(defun order (x d)
(cons (car x) (drink-list (cdr x) d))
)
(defun drink-list (x d)
(cond
((null x) ())
(t (cons (drink-count (car x) d) (drink-list (cdr x) d)))
)
)
(defun drink-count (x d)
(cond
((eq (car (cdr x)) d)
(cons (modify-count (car x) 1) (drink-count (cdr x) d)))
(t x)
)
)
(defun modify-count (x d)
(+ (parse-integer (subseq (write-to-string x) 0)) 1)
)

How to break a recursive call before going into a void error

(define l '(* - + 4))
(define (operator? x)
(or (equal? '+ x) (equal? '- x) (equal? '* x) (equal? '/ x)))
(define (tokes list)
(if (null? list)(write "empty")
(if (operator? (car list))
((write "operator")
(tokes (cdr list)))
(write "other"))))
The code works just fine til (tokes (cdr list))) reaches the end of file. Can someone give me a tip in how I can prevent that. I'm new at Scheme so I'm forgive me if the question is absurd.
You must make sure of advancing the recursion on each case (except the base case, when the list is null). In your code you're not making a recursive call for the (write "other") case. Also, you should use cond when there are several conditions to test, Let me explain with an example - instead of this:
(if condition1
exp1
(if condition2
exp2
(if condition3
exp3
exp4)))
Better write this, is much more readable and has the added benefit that you can write more than one expression after each condition without the need to use a begin form:
(cond (condition1 exp1) ; you can write additional expressions after exp1
(condition2 exp2) ; you can write additional expressions after exp2
(condition3 exp3) ; you can write additional expressions after exp3
(else exp4)) ; you can write additional expressions after exp4
... Which leads me to the next point, be aware that you can write only one expression for each branch of an if, if more than one expression is needed for a given condition in an if form then you must surround them with a begin, for example:
(if condition
; if the condition is true
(begin ; if more than one expression is needed
exp1 ; surround them with a begin
exp2)
; if the condition is false
(begin ; if more than one expression is needed
exp3 ; surround them with a begin
exp4))
Going back to your question - here's the general idea, fill-in the blanks:
(define (tokes list)
(cond ((null? list)
(write "empty"))
((operator? (car list))
(write "operator")
<???>) ; advance on the recursion
(else
(write "other")
<???>))) ; advance on the recursion

Resources