Scheme notation for "and" conditional - scheme

For an SICP course we are learning Scheme and we had an assignment that asked us to check if a point was in an axis-aligned rectangular. I did it like this:
(define in-rect?
(lambda (px py rx1 ry1 rx2 ry2)
(<= (* (- px rx1) (- px rx2)) 0) and
(<= (* (- py ry1) (- py ry2)) 0)))
I did this according to my previous C habits and forgot about Polish notation for a while there. The interpreter that our online tutor program uses runs this code "correctly", as I intended. However, AFAIK, this usage of 'and' should syntactically be wrong. DrRacket points out a syntax error when I try to run this.
Then how did this evaluate to correct values for every test case on the online tutor? Is this option also valid maybe?

The syntax for and is the same as for most expression - it uses prefix notation; also it can have zero or more arguments, which don't necessarily have to be boolean expressions:
(and <exp1> <exp2> <exp3> ...)
For your code it should look as follows:
(define in-rect?
(lambda (px py rx1 ry1 rx2 ry2)
(and (<= (* (- px rx1) (- px rx2)) 0)
(<= (* (- py ry1) (- py ry2)) 0))))
As to why your code seemed to work in the online tutor, it's because the interpreter probably evaluated the body of the lambda inside an implicit begin with three expression (first <= expression, and special form, second <= expression), returning just the value of the last condition. Although it's weird that it worked at all, because an and without arguments generally rises a "bad syntax" or similar error - it all depends on how it was implemented, but doesn't seem like a standards-compliant interpreter.
To make sure everything's clear, take a look at the documentation, because and behaves slightly different than what you'd expect, coming from a C background. Remember that and short-circuits at the first false condition:
(and (+ 1 1) #f (/ 1 0)) ; will work without a division by zero error
^
evaluation stops here
=> #f
And notice that and returns the value of the last expression it encounters, because in Scheme anything that is not explicitly #f, is considered true:
(and #t (* 2 3) (+ 1 1))
^
evaluation stops here
=> 2

(<= (* (- px rx1) (- px rx2)) 0)
and
(<= (* (- py ry1) (- py ry2)) 0)
Is actually three different (potential) values/expressions. Because you didn't wrap it in a begin, the interpreter might return the leftmost or the rightmost as the value of the lambda depending on your implementation.
Your online interpreter probably implemented and as a primitive function, rather than a macro or syntax, or simply isn't strick about not using macros/syntactic keywords as expressions.
If the interpreter thinks and has some sort of value (and/or is a valid expression) it can proceed to returning the value of the first of third expression in your lambda body.

Related

Function Definitions After Expressions in Scheme

I understand I can't define a function inside an expression, but I'm getting errors defining one after an expression within the same nested function. I'm using R5RS with DrScheme.
For example, this throws an error, 'define: not allowed in an expression context':
(define (cube x)
(if (= x 0) 0) ;just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
In R5RS you can only use define in rather specific places: in particular you can use it at the beginning (only) of forms which have a <body>. This is described in 5.2.2. That means in particular that internal defines can never occur after any other expression, even in a <body>.
Native Racket (or whatever the right name is for what you get with#lang racket) is much more flexible in this regard: what you are trying to do would (apart from the single-armed if) be legal in Racket.
You can use define inside another definition. Some Schemes won't allow you to have an if without the else part, though. This works for me:
(define (cube x)
(if (= x 0) 0 1) ; just for example, no reason to do this
(define (square x) (* x x))
(* x (square x)))
Have you tried making the definition at the beginning? maybe that could be a problem with your interpreter.
define inside a procedure body (that includes all forms that are syntactic sugar for procedures, like let, let*, and letrec) are only legal before other expressions and never after the first expression and it can not be the last form.
Your example shows no real reason for why you would want to have an expression before definitions. There is no way you can get anything more than moving all define up to the beginning. eg.
(define (cube x)
;; define moved to top
(define (square x) (* x x))
;; dead code moved under define and added missing alternative
(if (= x 0) 0 'undefined)
(* x (square x)))
If the code isn't dead. eg. it's the tail expression you can use let to make a new body:
(define (cube x)
(if (= x 0)
0
(let ()
;; this is top level in the let
(define (square x) (* x x))
;; required expression
(* x (square x)))))
I think perhaps we would need an example where you think it would be warranted to have the define after the expression and we'll be happy to show how to scheme it up.

Syntax for if-then-else in Racket

I have a problem with Racket.
(I'm using the tutorial at http://docs.racket-lang.org/guide/conditionals.html)
I tried to write a function that does this: If x is smaller than 4, then it should be incremented by 1, else it should be multiplied by 2.
(define (number x)
(if (< x 4) 'x+1 'x*2))
So I compiled it on DrRacket, but it does nothing. The (if (< x 5) 'x+1 'x*2)) -Part is marked black! I think the Problem is the ' thing.
In Lisps, the ' is a shorthand for the quote operator, which prevents an S-Expression or symbol from being evaluated. While x would normally be a variable, quoting it turns it into a kind of lightweight string. Quotes are not part of the if syntax. It makes no sense to use quoting in your case.
Furthermore, Lisps do not use infix operators. Addition is just an ordinary function and everything, including addition, is written as an S-Expression. So instead of x + 1 we would write (+ x 1).
So our function would then look like:
(define (number x)
(if (< x 4)
(+ x 1)
(* x 2)))

Why doesn't this Racket code terminate?

I'm reading about lazy evaluation and having trouble understanding a basic example they gave.
#lang racket
(define (bad-if x y z)
(if x y z))
(define (factorial-wrong x)
(bad-if (= x 0)
1
(* x (factorial-wrong (- x 1)))))
(factorial-wrong 4)
I'm a little confused as to why this program never terminates. I know the following code works just fine:
(define (factorial x)
(if (= x 0)
1
(* x (factorial (- x 1)))))
(factorial 4)
So I'm assuming it has something to do with scope. I tried step by step debugging and factorial-wrong executes the recursion function even when x is mapped to 0.
The standard if
(if test-expr then-expr else-expr)
will only evaluate either then-expr or else-expr, depending on test-expr, because this if is either a special form or a syntactic extension based on a special form, which means it doesn't follow the normal evaluation rules.
bad-if, on the other hand, is a standard procedure. In that case, Scheme first evaluates both expressions since they are parameters to the procedure bad-if before actually executing bad-if. So, even for x = 0, (* x (factorial -1)) will be evaluated, which will in turn evaluate (* x (factorial -2)) and so on, in an endless loop.
Use the stepper!
To be more specific:
Snip the #lang racket off the top of your program
Change the language level to "Intermediate Student"
Click on the Step button. Watch carefully to see where things go off the rails.

Why not letrec as fix?

In the paper Fixing Letrec: A Faithful Yet Efficient Implementation
of Scheme’s Recursive Binding Construct by Dybvig et al. it is said that (emphasis mine):
A theoretical solution to these problems is to restrict letrec so
that its left-hand sides are unassigned and right-hand sides are lambda
expressions. We refer to this form of letrec as fix, since it amounts to
a generalized form of fixpoint operator. The compiler can handle fix
expressions efficiently, and there can be no violations of the letrec
restriction with fix. Unfortunately, restricting letrec in this manner is not an option for the implementor and would in any case reduce the generality and convenience of the construct.
I have not scrutinized the R5RS report, but I have used letrec and the equivalent "named let" in Scheme programs and the unfortunate consequences mentioned in the paper are not clear to me, can someone enlighten me ?
The R5RS letrec restriction says something like these are in violation:
(let ((x 10))
(letrec ((x x))
x))
(letrec ((y (+ x 5))
(x 5))
(list x y))
Thus, it's not specified what would happen and it would certainly not be portable Scheme. It may evaluate to 10 and (5 10), the implementation might signal an error or you get an undefined value that might result in an error getting signaled. I have tested Racket, Gambit, Chicken and Ikarus and not one of them signal anything in the first case and they all evaluate to an unspecified value. Ikarus is the only one that returned (5 10) in the latter while the others all got contract errors since an unspecified value as argument violates +'s contract. (Ikarus always evaluates operands right to left)
The R[567]RS reports all state that if all expressions are lambda expressions you have nothing to worry about and I think that is the clue. Another is that you should not try to shadow like you would do with (named) let.
There is a follow up on the original paper that is entitled Fixing letrec (reloaded) that has macros that implements the "fix".
With equational syntax,
letrec x = init-x
y = init-y
body....
the restriction is that no RHS init... expression can cause evaluation of (or assignment to) any of the LHS variables, because all init...s are evaluated while all the variables are still unassigned. IOW no init... should reference any of the variables directly and immediately. It is OK of course for any of the init...s to contain lambda-expressions which can indeed reference any of the variables (that's the purpose of letrec after all). When these lambda-expressions will be evaluated, the variables will be already assigned the values of the evaluated init... expressions.
The authors say, to require all the RHSes to be lambda-expressions would simplify the implementation, because there's no chance for misbehaving code causing premature evaluation of LHS variables inside some RHS. But unfortunately, this changes letrec's semantics and thus is not an option. It would also prohibit simple use of outer variables in RHSes and thus this new cut-down letrec would also be less general and less convenient.
You also mention named let but it is not equivalent to letrec: its variables are bound as-if by let, only the looping function itself is bound via letrec:
(let ((x 1)(y 2))
(let g ((x x) (y x))
(if (> x 0) (g (- x y) y) (display x)))
(display x))
01
;Unspecified return value
(let ((x 1)(y 2))
(letrec ((g (lambda (x y)
(if (> x 0) (g (- x y) y) (display x)))))
(g x x)) ; no 'x' in letrec's frame, so refer to outer frame
(display x))
01
;Unspecified return value

Letrec and reentrant continuations

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.

Resources