In Scheme, does `or` and `and` short circuit? - scheme

Do and and or short circuit in Scheme?
The following are two implementation of lat? (list of atoms). One uses cond … else and the other uses or and and. I was wondering if they are equivalent and the answer to that hinges on whether or and and have short circuit evaluation in Scheme.
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
uses cond and else
(define lat?
(lambda (l)
(or (null? l)
(and (atom? (car l))
(lat? (cdr l))))))
uses or and and
I think or short-circuits. Why? I know (car ()) and (cdr ()) each produce Error: Attempt to apply…. If or didn’t short-circuit, then (lat? ()) would eventually evaluate (car ()) and produce the error. However, (lat? ()) does not produce the error, therefore (via Modus Tollens) or short-circuits. Is this correct? And does and short-circuit?

Yes, they both short-circuit per r6rs specification (didn't find html version of r7rs online but here a link to the pdf version of r7rs specification, see section 4.2):
If there are no <test>s, #t is returned. Otherwise, the expressions are evaluated from left to right until a <test> returns #f or the last <test> is reached. In the former case, the and expression returns #f without evaluating the remaining expressions. In the latter case, the last expression is evaluated and its values are returned.
and & or is subsequently defined in terms of test.

Related

The Little Schemer: `lat?` without `cond`?

One of the first questions in the second chapter of The Little Schemer (4th edition) asks the reader to write the function lat?, where (lat? l) returns true if l is a list of atoms.
It goes on to say:
You were not expected to be able to do this yet, because you are still missing some ingredients.
But I'm familiar with recursion, and the definition of atom? earlier in the book already introduced and (further implying the existence of or), so I gave it a shot anyway: (repl)
(define lat?
(lambda (l)
(or
(null? l)
(and
(atom? (car l))
(lat? (cdr l))))))
On the next page, the book introduces the cond operator to enable this definition of lat?:
(define lat?
(lambda (l)
(cond
((null? l) #t)
((atom? (car l)) (lat? (cdr l)))
(else #f))))
Is there any significant difference between these two implementations?
cond is a special form, that takes (roughly) the form
(cond
((test-expression) (then-expression))
((test-expression2) (then-expression2))
(else
(then-expression3)))
Its semantics is that it will evaluate the test-expressions in order, and for the first one that it finds to evaluate to #t (the true value), then it will evaluate its associated then-expression and return its value. If all the test-expressions evaluate to #f (the false value), and an else clause is present, then it will evaluate its associated then-expression3 in this case, and return its value.
So as far as semantics are concerned, the two implementations are equivalent. Their only difference might be that afaik the cond version is considered more idiomatic in the Scheme community.

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.

All: A Function Returning True if and only if All Elements of a List are True

I am looking for a built-in function in Racket that will return True iff all the items in a list are true.
I tried:
(define (all lst)
(when
(equal? lst '())
#t)
(if (not (car lst))
#f
(all (cdr lst))))
Giving error:
car: contract violation
expected: pair?
given: '()
A couple of testcases:
(all '(#t #f #t)) ; #f
(all '(#t #t #t)) ; #t
Could you please either fix it or point me to the built-in function?
(I googled, but got no meaningful result)
You've already accepted another answer that explains a nice way to do this, but I think it's worth pointing out what was wrong in your attempt, because it was actually very close. The problem is that true from the when block is completely ignored. It doesn't cause the function to return. So even when you have the empty list, you evaluate the when, and then keep on going into the other part where you call car and cdr with the same empty list:
(define (all lst)
(when ; The whole (when ...) expression
(equal? lst '()) ; is evaluated, and then its result
#t) ; is ignored.
(if (not (car lst))
#f
(all (cdr lst))))
A very quick solution would be to change it to:
(define (all lst)
(if (equal? lst '())
#t
(if (not (car lst))
#f
(all (cdr lst)))))
At that point, you can simplify a little bit by using boolean operators rather than returning true and false explicitly, and clean up a little bit by using empty?, as noted in the other answer:
(define (all lst)
(or (empty? lst)
(and (car lst)
(all (cdr lst)))))
You were actually very close at the start.
If you're looking for a builtin solution, you'll probably want to take a look at andmap, which applies a predicate over an entire list and ands the results together.
You could use this to implement all very simply.
(define (all lst)
(andmap identity lst))
By using identity from racket/function, all will just use the values in the list as-is. Instead of using identity explicitly, you could also use values, which is just the identity function on single values, so it's a somewhat common idiom in Racket.
There are two kinds of lists: empty ones and pairs.
Therefore we have the following structure:
(define (all xs)
(cond
[(empty? xs) ...]
[(pair? xs) ...]
[else (error 'all "expected a list, got: " xs)]))
Since all elements in the empty list are true, we get:
(define (all xs)
(cond
[(empty? xs) #t]
[(pair? xs) ...]
[else (error 'all "expected a list, got: " xs)]))
If a list begins with a pair, then all elements of the list are true,
if both the first element of the list and the rest of the elements of the list are true:
(define (all xs)
(cond
[(empty? xs) #t]
[(pair? xs) (and (first xs) (all (rest xs)))]
[else (error 'all "expected a list, got: " xs)]))
Note that part of the problem in your program is the use of when.
The result of
(when #t
'foo)
'bar
is 'bar. The construct when is only useful if you are using side effects (such as caused by set! and friends).
All is a higher order folding function. Scheme refers to these as "reductions" and reduce is available in SRFI-1
In Gauche Scheme:
(use srfi-1)
(define (all list-of-x)
(reduce (lambda (x y)
(and x y))
#t
list-of-x))
Will return #f or a value that evaluates to true. For example:
gosh> (all '(1 2 3))
1
If that's OK, then we're done. Otherwise we can always get #t with:
(use srfi-1)
(define (all-2 list-of-x)
(if (reduce (lambda (x y)
(and x y))
#t
list-of-x)
#t
#f))
And then wind up with:
gosh> (all '(1 2 3))
#t

Scheme evaluation order standard

I've got a program I'm writing for a class to substitute the left-most occurrence of a variable with a new variable. (It actually allows you to provide an equivalence relation yourself, as well). The thing is, in Chez Scheme 8.2, this substitutes the right-most occurrence, if the left most is inside a list. We use a server running some version of scheme (I'm not sure which version), and on the server it substitutes, correctly, the left-most occurrence. Below is the code:
(define subst-leftmost
(lambda (new old ls proc)
(let ([keep-going? #t])
(letrec ([helper
(lambda (ls)
(cond [(null? ls) ls]
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
[(and keep-going? (proc old (car ls)))
(set! keep-going? #f) (cons new (cdr ls))]
[else (cons (car ls) (helper (cdr ls)))]))]) (helper ls))))
This is called like so: (subst-leftmost 'x 'a '(d b c (a) b a) eq?) which should produce the output (d b c (x) b a), and does on the server. In Chez scheme, however, it produces (d b c (a) b x). I think the difference is due to the line
[(or (pair? (car ls)) (null? (car ls)))
(cons (helper (car ls)) (helper (cdr ls)))]
evaluating the helper of the car and the helper of the cdr in a not-set order.
My question is this: Which version of scheme is following the standard, and how can I modify my code so that it works correctly in both versions?
(I've already talked to my professor about this. He's going to address the class about it on Monday, once he can think about it some, but I'm curious. I also already got the full points for the assignment, so don't worry about the ethics of helping me, in that regard.)
There isn't any, sorry. Here's the relevant legalese. Use LETs or LET* if you need to evaluate sub-expressions in a particular order.
Scheme guarantees no specific order (as Cirno has said). If your code has no side-effects, this doesn't matter.
However, your code is side-effecting (because of the set! to an outside variable), so, you have some choices:
Use Racket (which is committed to using left-to-right order, last time I talked to a Racket dev)
Structure your code to remove side-effects, so that your helper function doesn't change any variable or state outside it
Use appropriate lets to ensure the ordering you need (as Cirno suggested); in particular, change (cons (helper (car ls)) (helper (cdr ls))) to:
(let ((depth-first (helper (car ls))))
(cons depth-first (helper (cdr ls))))

How I can force scheme to return #f explicitly instead of just void?

(define every-aux
(lambda(status predicate lst)
(cond((null? lst) status)
((cond((equal? (predicate (car lst)) #t)
(set! status #t)
(every-aux status predicate (cdr lst)))
(else (set! status #f) status))))))
Above Procedure returns void if predicate does not match with every element in lst?
It does not have any problem is returning #t though if predicate matches every element of lst.
Changing the last line to
(else (set! status #f) status))))))
to
(else (set! status "#f") status))))))
returns "#f" so procedure is correct.
How I can force scheme to return #f explicitly instead of just void?
Your code is very messy:
You have a cond inside another, but cond is intended for multiple tests/results.
There is no reason to have that status modified -- Scheme uses call-by-value, so this is likely not doing whatever you think it does.
Specifically, there is no reason to use (else (set! status #f) status) -- you could just return #f directly.
The actual reason for your confusion is the weird cond nesting -- the second cond is actually used as a test, so if you make it (the inner cond) return #f, then the whole test of the outer cond is getting #f, which means that it (the outer cond) didn't get any true result, and resorts to returning an unspecified value (and if this is Racket, then that value is shown as #<void>). So if you flatten the two conds into one, your problem will go away.
Finally, if you're having problems at such a level, then you should consider using some textbook to familiarize yourself with the language. Specifically HtDP is intended to give you an easy path into getting familiar with the syntax.
#Eli Barzilay
After some I deliberation I could see the solution. Thanks for the pointers.
(define every?
(lambda (predicate list)
(if(null? list) "Empty List not allowed."
(every-aux? predicate list))))
(define every-aux?
(lambda (predicate lst)
(cond ((null? lst) #t)
((equal? (predicate (car lst)) #t) (every-aux? predicate (cdr lst)))
(else #f))))

Resources