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))))
Related
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
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 :-)
I'm reading The Little Schemer. And thanks to my broken English, I was confused by this paragraph:
(cond ... ) also has the property of not considering all of its
arguments. Because of this property, however, neither (and ... ) nor
(or ... ) can be defined as functions in terms of (cond ... ), though
both (and ... ) and (or ... ) can be expressed as abbreviations of
(cond ... )-expressions:
(and a b) = (cond (a b) (else #f)
and
(or a b) = (cond (a #t) (else (b))
If I understand it correctly, it says (and ...) and (or ...) can be replaced by a (cond ...) expression, but cannot be defined as a function that contains (cond ...). Why is it so? Does it have anything to do with the variant arguments? Thanks.
p.s. I did some searching but only found that (cond ...) ignores the expressions when one of its conditions evaluate to #f.
Imagine you wrote if as a function/procedure rather than a user defined macro/syntax:
;; makes if in terms of cond
(define (my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))
;; example that works
(define (atom? x)
(my-if (not (pair? x))
#t
#f))
;; example that won't work
;; peano arithemtic
(define (add a b)
(my-if (zero? a)
b
(add (- a 1) (+ b 1))))
The problem with my-if is that as a procedure every argument gets evaluated before the procedure body gets executed. thus in atom? the parts (not (pair? x)), #t and #f were evaluated before the body of my-if gets executed.
For the last example means (add (- a 1) (+ b 1)) gets evaluated regardless of what a is, even when a is zero, so the procedure will never end.
You can make your own if with syntax:
(define-syntax my-if
(syntax-rules ()
((my-if predicate consequent alternative)
(cond (predicate consequent)
(else alternative)))))
Now, how you read this is the first part is a template where the predicate consequent and alternative represent unevaluated expressions. It's replaced with the other just reusing the expressions so that:
(my-if (check-something) (display 10) (display 20))
would be replaced with this:
(cond ((check-something) (display 10))
(else (display 20)))
With the procedure version of my-if both 10 and 20 would have been printed. This is how and and or is implemented as well.
You cannot define cond or and or or or if as functions because functions evaluate all their arguments. (You could define some of them as macros).
Read also the famous SICP and Lisp In Small Pieces (original in French).
So I've gotten rather simple task, in theory.
"Create a procedure where you take an integer as a parameter. If the integer is 0, return 0. If the integer is less than 0, return -1. If the integer is more than 0, return 1.
Solve this task without using if/cond(the only special forms allowed, are define, and, or)."
A very unpractical task, but a requirement for my course nonetheless. I've been stuck with this task for hours now, so I'd love some input!
Keep in mind that the procedure must return -1, 0 or 1. #t or #f are not good enough.
Both and and or are special versions of if. Eg.
(and a b) ; is the same as
(if a b #f)
(and a b c ...) ; is the same as
(if a (and b c ...) #f)
(or a b) ; is the same as
(if a
a ; though a is only evaluated once!
b)
(or a b c ...) ; is the same as
(if a
a ; though a is only evaluated once!
(or b c ...))
Notice that for 3 or more elements the result has and or or in it. You just apply the same transformation until you have something with just if.
If you want something like:
(if a 'x 'y)
You see that its obviously (or (and a 'x) 'y) since it turns into
(if (if a 'x #f)
(if a 'x #f)
'y)
Know that every value except #f is considered a true value. The basic method of doing this in "reverse" is knowing how and and or short circuits like if. If you need a special value returned instead of the result of a predicate you use and:
(and (null? x) 'empty-result)
If you need a false value to continue logic you use or
(or (and (null? x) 'empty-result)
(and (pair? x) 'pair-result))
If you need a default and have a or you just add it.
(or (and (null? x) 'empty-result)
(and (pair? x) 'pair-result)
'default-result)
If you happen to have and in the outer you need to wrap an or to get the default-result:
(or (and ...)
'default-result)
Good luck!
Here's a pretty simple implementation:
(define (signum n)
(or (and (zero? n) 0)
(and (positive? n) 1)
(and (negative? n) -1)))
Edit: I wrote my answer before I read Sylwester's post, but you should definitely read it for the theory of how this construction works.
Hi I have edited the code for function in scheme that checks whether the length of a list is even.
(define even-length?
(lambda (l)
(cond
((null? l)#f)
((equal? (remainder (length(l)) 2) 0) #t)
(else #f))))
Is it corrrect?
You seem to have the syntax for if and cond all mixed up. I suggest referring to the language reference. if only has two clauses, and you don't write else for the else clause. (Hint: You shouldn't need an if for this function at all.)
Also, consider whether it makes sense to return null if the list is null; probably you want to return #t or #f instead.
Oh yeah, and rewrite your call of length to be a proper prefix-style Scheme function call.
The code is clearly wrong -- your %2 assuming infix notation, where Scheme uses prefix notation. The syntax of your if is wrong as well -- for an if, the else is implicit (i.e. you have if condition true-expression false-expression. In this case, you're trying to return #t from one leg and #f from another leg -- that's quite unnecessary. You can just return the expression that you tested in the if.
Edit: one other detail -- you should really rename this to something like even-length?. Even if I assume that it's a predicate, a name like even would imply to me that (even 3) should return #f, and (even 4) should return #t -- but in this case, neither works at all.
Edit2: Since mquander already gave you one version of the code, I guess one more won't hurt. I'd write it like:
(define (even-length? L) (even? (length L)))
I don't like using lower-case 'l' (but itself) much, so I've capitalized it. Since even? is built in, I've used that instead of finding the remainder.
Running this produces:
> (even-length? `(1 2 3))
#f
> (even-length? `(1 2 3 4))
#t
>
This is different from what you had in one respect: the length of an empty list is 0, which is considered an even number, so:
(even-length? `())
gives #t.
(define even-length? (lambda (l)
(even? (length l))))
Usage:
(even-length? '(1 2 3 4))
#t
(even-length? '(1 2 3 ))
#f
As others pointed out, there is indeed a predicate to check evenness of a number, so why not using it?
EDIT: I just saw Jerry Coffin wrote the same function witht the same example... Sorry for repeating :-)