Will a procedure be considered as a predicate, <p> , when the special form cond is missing the key word else? - scheme

I accidentally forgot to put the else in the following cond expression, and something strange occurred.
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(+ 1 2 1001)
))
> (abs 1)
1001
>
the result of (abs 1) is not the result of (+ 1 2 1001),which is 1004, but the last element of the arguments of the expression (+ 1 2 1001).
the cond form is
(cond (<p1>,<e1>)
(<p2>,<e2>)
(<p3>,<e3>)
...
(<pn>,<en>))
there is no predicate in the expression (+ 1 2 1001), so I wonder if the procedure + has been considered as predicate, and if it always evaluates as true, selecting the last element to return. Is that how it works???

Sequencing: begin form in Racket allows you to sequence multiple expressions. It evaluates each expression from left to right and the final result is the last expression.
Syntax: The syntax for cond shows that multiple expressions can be sequenced in the rhs of a clause without a begin. Such a thing is called an implicit begin.
Semantics: According to the documentation, cond evaluates the rhs of a clause if the lhs is anything but #f. Therefore + in the position of the test-expression evaluates the rhs of the clause.
Style: By convention, using square brackets in a few key places makes Racket code even more readable. The clause of a cond is one of these places.
The following snippet is equivalent to your snippet:
#lang racket
(define (abs x)
(cond [(< x 0) x]
[(= x 0) 0]
[+ (begin 1
2
1001)]))
(abs 1)
; => 1001

cond works like this:
(cond (test-expr then-body)
(test-expr2 then-body2)
(else then-body3))
The test-exprs are tested one by one, and the first test-expr that returns a non-false value causes its corresponding then-body to be executed. The last value in the executed then-body is the value of the whole cond.
In Scheme, anything not #f is considered true. Therefore, + is considered true. In your cond, + acts like an else because it is always true. In fact, your code could be written like this without any change in behavior:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(else 1 2 1001)))
In your original code, the first test-expr that returns a non-false value is +. Since 1001 is the last value of the executed then-body, 1001 is the value of the whole cond. That's why you got 1001.

cond is a way to do if-elseif*-else in lisp and getting a flatter structure than with nesting of if. Since cond is derived form you could write your conditional in terms of if. Your procedure would become:
(define (abs x)
(if (< x 0)
x
(if (= x 0)
0
(if +
(begin
1
2
1001)))))
The last if checks if + is truthy. Every expression not evaluating to #f is truthy so all procedures are truty. It will then evaluate every part 1, 2, then 1001 and since that is the tail expression that is the result of the evaluation. You can have as many consequences in each cond term, but all before the tail is just for effect.
You could add one extra pair of parentheses and it would work as you expected:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
((+ 1 2 1001))))
Here it has no addictional consequences and the truthy result of the predicate is the result for (abs 1). One would want the code to be as clear as possible so using else here is a much better option:
(define (abs x)
(cond ((< x 0) x)
((= x 0) 0)
(else (+ 1 2 1001))))
This helps with another problem as well. While a number is always thruthy if you do the predicate trick with something that may be #f the result is undefined in the spec. Thus:
(cond ((other-proc x)))
; ==> ??
If the call to other-proc is truthy the result is that, if it is #f you get the result chosen by the implementers. These are almost always truthy values with crazy visualizations like #<undefined> but can be anything like "BaNaNa" or even #f. Thus it is wise to have an else term so that you and not some other developer gets to choose the outcome :-)

Related

Understanding how a sequence works

I have the following accumulate function:
; accumulate
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence) (accumulate op initial (cdr sequence)))))
I'm trying to write a length function to get the length of a sequence using the accumulate function.
For the function to plug into accumulate, why is it (+ y 1) instead of (+ x 1) ? That's the part I can't figure out:
(define (length sequence)
(accumulate (lambda (x y) (+ x 1)) ; wrong
0
sequence))
(define (length sequence)
(accumulate (lambda (x y) (+ y 1)) ; correct
0
sequence))
Your problem is that x and y doesn't tell you anything what it is. However if you look at accumulate you can see how op is called:
(op (car sequence) ; first argument is the element
(accumulate op initial (cdr sequence))) ; second argument is the accumulated value
While it doesn't really look that way Imagine that the second argument is calling accumulate on the empty sequence. Then you get this:
(op (car sequence)
initial)
So lets make length:
(define (length sequence)
(accumulate (lambda (element initial)
;; initial is often also called acc / accumulator
(+ 1 initial))
0
sequence))
So the answer is that the first argument is the individual element while the second is either the initial value (0) or the previous calculated value which is 0 with as many 1 added as the tail of the sequence had. Thus a number. WHy you don't use the first argument is that you can't really use "a" or whatever the list contains to count elements since you need to just count them not use them as values. If you use the first argument and it happens to be strings what is (+ "a" 0) supposed to help in finding out that the list has length 1?
If you use (lambda (x y) (+ x 1)) as op, then your length (or to be precise, the accumulate) function will not use the result of the recursive calls to the accumulate function. It will essentially only do one computation, (+ x 1) ,where x is (car sequence), the first element of sequence -- and this one computation may or may not even make sense, depending on whether or not x is a number, and even if it did the answer would be wrong.
On the other hand, if op is (lambda (x y) (+ y 1)), then your function will replace
(op (car sequence) (accumulate op initial (cdr sequence)))
with
(+ (accumulate op initial (cdr sequence)) 1)
The recursion bottoms out with the computation (+ 0 1), so you ultimately get the length of the list, when each of the nested recursive calls to accumulate return the length of the sub-lists to their calling functions.

Taking the 'and' of a list by folding in Scheme

In the book Structure and Interpretation of Computer Programs
by H. Abelson and G. J. Sussman with J. Sussman,
the accumulation or fold-right is introduced in Section 2.2.3 as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
I tried to use this to take the and of a list of Boolean variables, by writing:
(accumulate and
true
(list true true false))
However, this gave me the error and: bad syntax in DrRacket (with #lang sicp),
and I had to do this instead:
(accumulate (lambda (x y) (and x y))
true
(list true true false))
Why? I believe it has something to do with how and is a special form,
but I don't understand Scheme enough to say.
Perhaps I'm just missing some obvious mistake...
You answered your own question: and is a special form (not a normal procedure!) with special evaluation rules, and accumulate expects a normal procedure, so you need to wrap it inside a procedure.
To see why and is a special form, consider these examples that demonstrate that and requires special evaluation rules (unlike procedures), because it short-circuits whenever it finds a false value:
; division by zero never gets executed
(and #f (/ 1 0))
=> #f
; division by zero gets executed during procedure invocation
((lambda (x y) (and x y)) #f (/ 1 0))
=> /: division by zero

How to return a function in scheme (racket) using conditionals?

How do I return a function using conditionals in scheme? What I want to do is to return the product of 2 numbers (when r = 0), or the sum (when r=1) or the difference (when r=2) or 0 (otherwise) depending on the value of r.
What I tried is below, but the return value is always 0. How do I fix that?
(define (f r)( lambda (x y)
(cond (equal? r 0)
((* x y))
( (equal? r 1)
( (+ x y)))
( (equal? r 2))
( (- x y))
(else
0 ))))
(( f 0) 2 3)
I would expect 6, but I get 0. Thanks in advance.
cond works like this:
(cond (test-expr then-body)
(test-expr2 then-body2)
(else then-body3))
The test-exprs are tested one by one, and the first test-expr that returns a non-false value causes its corresponding then-body to be executed. The last value in the executed then-body is the value of the whole cond.
To know why you got 0 (and not 6), look carefully at your first cond clause: (cond (equal? r 0) ...). equal? is the test-expr, and since equal? itself is not false, its then-body is executed (i.e. r and 0 are executed). Since 0 is the last value in the then-body, 0 is the value of the whole cond. That's why you got 0.
Note that nearly all lines in your cond have parentheses that have been incorrectly placed. Here's a fixed version:
(define (f r)
(lambda (x y)
(cond ((equal? r 0) ; <- Parentheses fixed.
(* x y)) ; <- Parentheses fixed.
((equal? r 1) ; <- Parentheses fixed.
(+ x y)) ; <- Parentheses fixed.
((equal? r 2) ; <- Parentheses fixed.
(- x y)) ; <- Parentheses fixed.
(else 0))))
Here's an arguably better way to define the same function:
(define (f r)
(cond ((= r 0) *)
((= r 1) +)
((= r 2) -)
(else (lambda _ 0))))
For example:
((f 0) 2 3)
;; '(f 0)' returns '*', so this reduces to: (* 2 3)
;; Answer:
6
This version is technically better as it is not restricted to taking only two arguments. For example, you can now do this: ((f 1) 1 2 3 4 5 6) (reduces to (+ 1 2 3 4 5 6)).
The cond expression in your code has some syntax errors:
There are brackets missing in each condition
You must not surround a procedure application with double brackets, this is a mistake: ((* x y))
Notice that you require to return an arithmetic procedure and, for example, we can simply return + which is similar to returning (lambda (x y) (+ x y)) (except that it'll work for more than two parameters, but that's a win!).
Bear in mind that in Racket the solution can be written in a more concise way: for example, by using case to simplify the conditions and const for the last case, when we want to return a procedure that returns 0 no matter what are the parameters. Here's how:
(define (f r)
(case r
((0) *)
((1) +)
((2) -)
(else (const 0))))
It works as expected, by returning a procedure that you can apply to the given arguments:
((f 0) 6 7)
=> 42
((f 3) 2 3)
=> 0

How do I use and/or instead of if/cond?

I'm new to Scheme programming and I've gotten this task that I just can't find out how to work correctly. I'm supposed to define a procedure with one parameter (a number). If the number is positive I want 1 to be returned, -1 if the number is negative and 0 if it is 0, using only and/or. If and cond is not allowed. I only get #t or #f returned, but you see that's not what I want. Any help or pointers is appreciated
You can solve your problem if you look at the following equivalence, valid when every expj has a value different from #f:
(cond (test1 exp1) (or (and test1 exp1)
(test2 exp2) (and test2 exp2)
... ≡ ...
(testn expn) (and testn expn)
(else expn+1)) expn+1)
Since the function that gets the sign of a number can simply be written in this way:
(define (sign x)
(cond ((> x 0) +1)
((< x 0) -1)
(else 0)))
after applying the above equivalence, since every result is an integer, different from #f, this function becomes equal to the solution proposed also in another answer:
(define (sign x)
(or (and (> x 0) +1)
(and (< x 0) -1)
0))
So, which is the reason of the above equivalence? It depends on the fact that and evaluates its arguments in turn; as soon as one of them is #f, it stops by returning #f, otherwise returns its last argument (and this explains the single branches (and testj expj)); while or evaluates its arguments in turn; as soon as one of them is not #f, it stops by returning it, otherwise returns its last argument (and this explains the chain (or (and ...) (and ...) ... expn+1)).
(define test
(lambda (n)
(or (and (< n 0) -1)
(and (= n 0) 0)
1)))
Part of the trick is understanding that and, if everything evaluates to true, will return the last item it evaluated, while or will return the first thing that successfully evaluates to true. The other part is realizing that everything except for #f is considered "true."
The transformation of and is seen in the report but to not include the actual macros it's basically this:
; only one argument
(and a) ; ===>
a
; one of more
(and a b ...) ; ==>
(if a
(and b ...)
#f)
All arguments must be evaluate to a positive value and the last value is the result, else #f. It short circuits so when something is #f the rest of the expressions are never evaluated.
For or is like this:
(or a) ; ==>
a
(or a b ...) ; ==>
(let ((a-value a))
(if a-value
a-value
(or b ...)))
The first argument that does not evaluate to #f gets returned. If all values are #f the last #f will be the result.
Thus if you want:
(if a b c) ; ==>
(let ((tmpa a))
(or (and atmpa b)
(and (not atmpa) c)) ; not part only important if b can be #f
I use let to prevent evaluating the same expression several times. eg. if you had one that printed something like (begin (display "hello") #f) or it's an expensive calculation then it's necessary or else you can just substitute the variable with the expression. eg. the last would become:
(or (and a b)
(and (not a) c))
That transformed back with no temporary variables become:
(if (if a b #f)
(if a b #f)
(if (not a) c #f))
If b is #f value, then the result is #f because of the last if. Thus everytime a is true b is the result. Everytime it's false, c is the answer. Thus
(if a b c)
So imagine you want to return the first true value in a list.
(define (first-true lst)
(and (not (null? lst))
(car lst)
(first-true (cdr lst))))

Compile/Evaluate operands in tailposition

I have a project for school for which I'm supposed to optimize a compiler/evaluator for Scheme.
The task is to implement tail-call optimization wherever possible.
I'm aware of the known tail-call optimization as shown below:
(define (f x)
<send some rockets into space>
(f (+ x 1)))
However, I'm thinking about evaluating operands in tail position as well. Suppose the following:
; The function
(define (f a b c)
<send some monkeys into space>
1)
; Call the function with (f 3 4 5)
(f (+ 1 2) (begin (define x 4) x) 5))
Evaluating the operands (+ 1 2), (begin (define x 4)) and 5 could be done in tail position, right?
Each of the operands are evaluated in their own environment. I tried this by using the regular R5RS in DrRacket with the following expression:
(+ (begin (define x 5) x) x)
If the operands would be evaluated in the same environment I would be able to pass the x defined in the first operand as the second operand. This is however not possible.
So, is it correct for me to assume that each operand can be evaluated in tail position?
"Tail position" is always relative to some outer expression. For example, consider this:
(define (norm . args)
(define (sum-of-squares sum args)
(if (null? args)
sum
(let ((arg (car args)))
(sum-of-squares (+ sum (* arg arg)) (cdr args)))))
(sqrt (sum-of-squares 0 args)))
The recursive call to sum-of-squares is indeed in tail position relative to sum-of-squares. But is it in tail position relative to norm? No, because the return value from sum-of-squares is sent to sqrt, not directly to norm's caller.
The key to analysing whether an expression A is in tail position relative to outer expression B, is to see whether A's return value is directly returned by B, without any further processing.
In your case, with your expression (f (+ 1 2) (begin (define x 4) x) 5) (which isn't actually valid, by the way: perhaps you meant (f (+ 1 2) (let () (define x 4) x) 5) instead), none of the subexpressions (+ 1 2), (let () (define x 4) x), and 5 are in tail position with respect to f, since their values have to be collected first, and then passed to f (which is a tail call).
None of the operands of an application (op1 op2 ...) is in tail position.
For R5RS Scheme you can see the position in which an application occurs in a tail context here:
https://groups.csail.mit.edu/mac/ftpdir/scheme-reports/r5rs-html.old/r5rs_22.html
So I finally figured it out.
In regular R6RS operands can never be evaluated in tail position because R6RS specifies that there is no strict order in which they are evaluated.
However, in this self-built evaluator for Scheme I do specify the order in which they are evaluated. Ergo, I can strictly define which operator is the last one, and that one can be evaluated in tail position.

Resources