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
Related
Define a procedure "and", implementing the Boolean and-function for our procedures true and false - (test (and p q)) should evaluate to true exactly when both p and q are true. Use only function application and lambda expressions.
(define (and p q)
(if eq? p q)
((true #t #f)
((false) #t #f)))
Be aware that and is a special form with different evaluation rules, and we can not truly implement it using just procedures: we need special syntax for it - say, by defining it using a macro. To see this, notice that the built-in special form and will not raise an error when we do this:
(and #f (/ 1 0))
=> #f
If we write and as a procedure, the above line will result in an error, because the second parameter is in fact evaluated before calling the procedure:
(and #f (/ 1 0))
=> /: division by zero
Now that the above is clear, remember that in Scheme the only false value is #f, everything else is considered truthy. With this in mind, a standard and special form invoked with two parameters behaves as follows (ignoring the difference in the evaluation rules), notice that the value of the expression is the value of q, unless p is false:
(define (and p q)
(if (false? p)
p
q))
But if we want to enforce that only true or false values are returned, we have to change the last line:
(define (and p q)
(if (false? p)
p
(not (false? q))))
A variable p is false if it has the value #f and it can be used in if:
(define (and-function p q)
(if p
q
#f))
This checks wether p is true or not. If it's true the result is q. If not the result should be #f, the same as p.
Know that and in Scheme is short circuiting and not a function at all, but I guess you book will come to that.
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))))
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.
I have been told that the following expression is intended to evaluate to 0, but that many implementations of Scheme evaluate it as 1:
(let ((cont #f))
(letrec ((x (call-with-current-continuation (lambda (c) (set! cont c) 0)))
(y (call-with-current-continuation (lambda (c) (set! cont c) 0))))
(if cont
(let ((c cont))
(set! cont #f)
(set! x 1)
(set! y 1)
(c 0))
(+ x y))))
I must admit that I cannot tell where even to start with this. I understand the basics of continuations and call/cc, but can I get a detailed explanation of this expression?
This is an interesting fragment. I came across this question because I was searching for discussions of the exact differences between letrec and letrec*, and how these varied between different versions of the Scheme reports, and different Scheme implementations. While experimenting with this fragment, I did some research and will report the results here.
If you mentally walk through the execution of this fragment, two questions should be salient to you:
Q1. In what order are the initialization clauses for x and y evaluated?
Q2. Are all the initialization clauses evaluated first, and their results cached, and then all the assignments to x and y performed afterwards? Or are some of the assignments made before some of the initialization clauses have been evaluated?
For letrec, the Scheme reports say that the answer to Q1 is "unspecified." Most implementations will in fact evaluate the clauses in left-to-right order; but you shouldn't rely on that behavior.
Scheme R6RS and R7RS introduce a new binding construction letrec* that does specify left-to-right evaluation order. It also differs in some other ways from letrec, as we'll see below.
Returning to letrec, the Scheme reports going back at least as far as R5RS seem to specify that the answer to Q2 is "evaluate all the initialization clauses before making any of the assignments." I say "seem to specify" because the language isn't as explicit about this being required as it might be. As a matter of fact, many Scheme implementations don't conform to this requirement. And this is what's responsible for the difference between the "intended" and "observed" behavior wrt your fragment.
Let's walk through your fragment, with Q2 in mind. First we set aside two "locations" (reference cells) for x and y to be bound to. Then we evaluate one of the initialization clauses. Let's say it's the clause for x, though as I said, with letrec it could be either one. We save the continuation of this evaluation into cont. The result of this evaluation is 0. Now, depending on the answer to Q2, we either assign that result immediately to x or we cache it to make the assignment later. Next we evaluate the other initialization clause. We save its continuation into cont, overwriting the previous one. The result of this evaluation is 0. Now all of the initialization clauses have been evaluated. Depending on the answer to Q2, we might at this point assign the cached result 0 to x; or the assignment to x may have already occurred. In either case, the assignment to y takes place now.
Then we begin evaluating the main body of the (letrec (...) ...) expression (for the first time). There is a continuation stored in cont, so we retrieve it into c, then clear cont and set! each of x and y to 1. Then we invoke the retrieved continuation with the value 0. This goes back to the last-evaluated initialization clause---which we've assumed to be y's. The argument we supply to the continuation is then used in place of the (call-with-current-continuation (lambda (c) (set! cont c) 0)), and will be assigned to y. Depending on the answer to Q2, the assignment of 0 to x may or may not take place (again) at this point.
Then we begin evaluating the main body of the (letrec (...) ...) expression (for the second time). Now cont is #f, so we get (+ x y). Which will be either (+ 1 0) or (+ 0 0), depending on whether 0 was re-assigned to x when we invoked the saved continuation.
You can trace this behavior by decorating your fragment with some display calls, for example like this:
(let ((cont #f))
(letrec ((x (begin (display (list 'xinit x y cont)) (call-with-current-continuation (lambda (c) (set! cont c) 0))))
(y (begin (display (list 'yinit x y cont)) (call-with-current-continuation (lambda (c) (set! cont c) 0)))))
(display (list 'body x y cont))
(if cont
(let ((c cont))
(set! cont #f)
(set! x 1)
(set! y 1)
(c 'new))
(cons x y))))
I also replaced (+ x y) with (cons x y), and invoked the continuation with the argument 'new instead of 0.
I ran that fragment in Racket 5.2 using a couple of different "language modes", and also in Chicken 4.7. Here are the results. Both implementations evaluated the x init clause first and the y clause second, though as I said this behavior is unspecified.
Racket with #lang r5rs and #lang r6rs conforms to the spec for Q2, and so we get the "intended" result of re-assigning 0 to the other variable when the continuation is invoked. (When experimenting with r6rs, I needed to wrap the final result in a display to see what it would be.)
Here is the trace output:
(xinit #<undefined> #<undefined> #f)
(yinit #<undefined> #<undefined> #<continuation>)
(body 0 0 #<continuation>)
(body 0 new #f)
(0 . new)
Racket with #lang racket and Chicken don't conform to that. Instead, after each initialization clause is evaluated, it gets assigned to the corresponding variable. So when the continuation is invoked, it only ends up re-assigning a value to the final value.
Here is the trace output, with some added comments:
(xinit #<undefined> #<undefined> #f)
(yinit 0 #<undefined> #<continuation>) ; note that x has already been assigned
(body 0 0 #<continuation>)
(body 1 new #f) ; so now x is not re-assigned
(1 . new)
Now, as to what the Scheme reports really do require. Here is the relevant section from R5RS:
library syntax: (letrec <bindings> <body>)
Syntax: <Bindings> should have the form
((<variable1> <init1>) ...),
and <body> should be a sequence of one or more expressions. It is an error
for a <variable> to appear more than once in the list of variables being bound.
Semantics: The <variable>s are bound to fresh locations holding undefined
values, the <init>s are evaluated in the resulting environment (in some
unspecified order), each <variable> is assigned to the result of the
corresponding <init>, the <body> is evaluated in the resulting environment, and
the value(s) of the last expression in <body> is(are) returned. Each binding of
a <variable> has the entire letrec expression as its region, making it possible
to define mutually recursive procedures.
(letrec ((even?
(lambda (n)
(if (zero? n)
#t
(odd? (- n 1)))))
(odd?
(lambda (n)
(if (zero? n)
#f
(even? (- n 1))))))
(even? 88))
===> #t
One restriction on letrec is very important: it must be possible to evaluate
each <init> without assigning or referring to the value of any <variable>. If
this restriction is violated, then it is an error. The restriction is necessary
because Scheme passes arguments by value rather than by name. In the most
common uses of letrec, all the <init>s are lambda expressions and the
restriction is satisfied automatically.
The first sentence of the "Semantics" sections sounds like it requires all the assignments to happen after all the initialization clauses have been evaluated; though, as I said earlier, this isn't as explicit as it might be.
In R6RS and R7RS, the only substantial changes to this part of the specification is the addition of a requirement that:
the continuation of each <init> should not be invoked more than once.
R6RS and R7RS also add another binding construction, though: letrec*. This differs from letrec in two ways. First, it does specify a left-to-right evaluation order. Correlatively, the "restriction" noted above can be relaxed somewhat. It's now okay to reference the values of variables that have already been assigned their initial values:
It must be possible to evaluate each <init> without assigning or
referring to the value of the corresponding <variable> or the
<variable> of any of the bindings that follow it in <bindings>.
The second difference is with respect to our Q2. With letrec*, the specification now requires that the assignments take place after each initialization clause is evaluated. Here is the first paragraph of the "Semantics" from R7RS (draft 6):
Semantics: The <variable>s are bound to fresh locations, each
<variable> is assigned in left-to-right order to the result of evaluating
the corresponding <init>, the <body> is evaluated in the resulting
environment, and the values of the last expression in <body> are
returned. Despite the left-to-right evaluation and assignment order, each
binding of a <variable> has the entire letrec* expression as its region,
making it possible to define mutually recursive procedures.
So Chicken, and Racket using #lang racket---and many other implementations---seem in fact to implement their letrecs as letrec*s.
The reason for this being evaluated to 1 is because of (set! x 1). If instead of 1 you set x to 0 then it will result in zero. This is because the continuation variable cont which is storing the continuation is actually storing the continuation for y and not for x as it is being set to y's continuation after x's.
I am trying to write a function that can check whether or not some input is a quotation for a syntax checker.
I have the following code:
(define is-quote-expression?
(lambda (v)
(equal? (car v) 'quote)
(is-quotation? (cdr v)))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v)
(and (pair? v)
(is-quotation? (car v))
(is-quotation? (cdr v)))))
When I try to evaluate, I get the following:
(is-quote-expression? '1)
#f
(is-quote-expression? (cons 'quote 1))
#t
I think my TA told me that the Scheme environment replaced all "'" with "'quote", however, this does not seem to be the case. We are running Petite Chez Scheme.
What am I not seeing?
Thanks in advance.
There are a couple of problems with your code, for starters the (lambda (pair? v) part in is-quote-expression? is almost certainly a mistake (you're defining a lambda with two parameters called pair? and v).
Also, I believe you intended to call is-quotation? from is-quote-expression? only if v isn't a pair, so it doesn't make sense to ask again if (pair? v) in is-quotation?. And who said that a pair is a quotation only if both its car and cdr are quotations?
Here, I believe this is what you intended:
(define is-quote-expression?
(lambda (v)
(if (pair? v)
(equal? (car v) 'quote)
(is-quotation? v))))
(define is-quotation?
(lambda (v)
(or (number? v)
(boolean? v)
(char? v)
(string? v)
(symbol? v)
(null? v))))
I agree with Óscar's post, though, is-quote-expression? accepts a list rather than a pair and returns whether it was a quotation.
(define is-quote-expression?
(lambda (v)
(and (proper-list-of-given-length? v 2)
(equal? (car v) 'quote)
(is-quotation? (cadr v)))))
Also, your original question shows some confusion as to what quote actually does. This is what really should happen:
> (is-quote-expression? '1)
#f
> (is-quote-expression? (cons 'quote 1))
#f
> (is-quote-expression? (quote 42))
#f
> (is-quote-expression? (quote (quote 42)))
#t
Note how the built-in quote procedure simply returns what it is passed. In the case of (quote 42) it simply returns 42. But (quote (quote 42)) returns (quote 42), which is what you wish to pass to is-quote-expression?.
The behavior of quote is specified in R6RS, appendix A.3. For '1, the relevant rule is 6sqv:
(store (sf1 ...) S1[ 'sqv1 ]) → (store (sf1 ...) S1[ sqv1 ])
Time to break this down.
The "S → T" notation defines one step in evaluating a term, where "S" evaluates to "T".
Since store and the sf1 non-terminals appear the same on both the left and right sides, you don't need to understand them to understand how '1 evaluates. If you need something, think of store as "storage environment" and the sfn as pairs of names and values; (store ((x 1) (y 2)) S) means the identifier x is associated with the value 1 and y with 2 when evaluating the term S.
If you're not familiar with the S[e] notation, it refers to a term with one "hole" (an term with a [] in it) filled with e. There are two related syntax elements: terms with holes (S[]) and terms with a hole filled by a value (S[e]). Holes are a little (but only a little) like unnamed variables. One important difference is that a term is allowed only one hole. Holes are perhaps best explained by example. All of the following are S[]:
(+ [] 1 2)
(list [] 'a "foo")
(cond ((= x 0) [])
((> x 0) 1)
(else -1))
Note that a hole can only appear where a sub-term is syntactically valid; [] 2) is not a term-with-hole. S[0] would be a term with 0 substituted into the hole:
(+ 0 1 2)
(list 0 'a "foo")
(cond ((= x 0) 0)
((> x 0) 1)
(else -1))
When a value is given for a hole, the term S[] is also called a "context". This comes from one of the primary uses for terms-with-holes: to match any term containing the given value. S[e] is any term that contains e as a valid sub-term, so S[] is the context that e appears in. In short, S1['sqv1] is a stand-in for any term that contains a quote.
(+ 'foo 1 2)
(list 'bar 'a "foo")
(cond ((= x 0) 'baz)
((> x 0) 1)
(else -1))
Note the second term provides two different contexts for quote-terms: (list [] 'a "foo"), (list 'bar [] "foo"). This suggests that you shouldn't think of holes too much as just being unnamed variables.
If you're wonder why context terms and holes are used, they're an alternative to recursive definitions. Without contexts, → would have to be defined recursively over the structure of terms (Scheme's grammar defines the structure). Substitution in lambda calculus is an example of structural recursion, as are any tree-processing functions you might define in Scheme (though Scheme syntax is quite different than the syntax used to define → and lambda calculus substitution).
(define (tree-depth tree)
(if (pair? tree)
(max (tree-depth (car tree))
(tree-depth (cdr tree)))
1
) )
Next, let's examine the meaning of sqv, which is short for "self-quoting values". This is a non-terminal from the Scheme grammar, given in appendix A.2.
sqv ::= n | #t | #f
n ::= [numbers]
sqv is simply a number or boolean.
All together, the 6sqv evaluation rule means that a quoted number or boolean evaluates to the number or boolean; the quote is simply discarded.
What this signifies for your homework is that you can't tell the difference between 1 and '1 with a normal function, since sub-terms are evaluated before the function is called. You'll need a macro.
Why go through all this just to say that "'1 evaluates to 1"? Firstly, answering "why" takes more than answering "what". Also, it will hopefully help you go beyond the question, learning a little bit how to read Scheme's formal semantics, give you a taste of computational theory concepts and lead to many more questions.