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.
Related
In the following code:
(define x 14)
(display x) ; x = 14
(set! x 13)
(display x) ; x = 13
(define x 14)
(display x) ; x = 14
(set! y 13) ; SchemeError: y not found!
(display y)
What we a use case where someone would want to use set! over just define, if define can be used for everything that set! can be used for + the actual definition itself?
define creates a new binding between a name and a value (a variable), set! mutates an existing binding. These are not the same operation, languages like Python which confuse the operations notwithstanding.
In particular something like
(define x 1)
...
(define x 2)
is illegal: you can only create the variable once. Implementations may not check this, but that doesn't make it legal. Once you've created the binding, if you want to modify it you need to do that with set!.
A particular case where implementations (including Racket) are intentionally sloppy about this is when they are being used interactively. Quite often if you're interacting with the system you may want to say, for instance:
> (define square (λ (x) (+ x x)))
... ooops, that's not right, is it?
... Better fix it using the command-line editing
> (define square (λ (x) (* x x)))
In cases like that it's clearly better for the implementation just to allow this repeated definition of things, because it's going to make the life of users enormously easier.
But in programs such repeated definitions in the same scope are (almost?) always bugs, and they really ought to be caught: if you want to mutate a binding, use set!. Racket in particular will certainly puke on these.
Finally note that define is simply not legal in all the places set! is: even in Racket (which allows define in many more places than Scheme does) this is not even slightly legal code:
(define (foo x)
(define v x)
(if (odd? x)
(define v (* v 2))
(define v (/ v 2)))
v)
While this is
(define (foo x)
(define v x)
(if (odd? x)
(set! v (* v 2))
(set! v (/ v 2)))
v)
(It's still terrible code, but it is legal.).
This question already has an answer here:
Turning structural recursion into accumulative recursion in Racket
(1 answer)
Closed 4 years ago.
Is it possible to perform tail call optimization by the compiler/interpreter for the factorial function given below?
(define factorial
(lambda (x)
(if (= x 0)
1
(* x (factorial (- x 1))))))
I would like to get a brief explanation for the same.
From the comment by #rsm below I understand program should be written something like this:
(define fact
(lambda (x accumulator)
(if (<= x 1)
accumulator
(fact (- x 1) (* x accumulator)))))
(define factorial
(lambda (x)
(fact x 1)))
Or something like this:
(define factorial
(lambda (n)
(let fact ([i n] [a 1])
(if (= i 1)
a
(fact (- i 1) (* a i))))))
First, a terminological issue: you, as the programmer, cannot "do" tail call optimization. (This is one of the reasons why "tail call optimization" is a bad name for this property.) In this case, the "optimization" is done by the evaluator; specifically, a correct evaluator for Racket or Scheme or any properly tail-calling language makes a promise: it promises not to use unbounded memory on certain types of programs. Specifically, programs that make only "tail calls."
So, what you're really asking is how you can convert your program to one that makes only tail calls. The key here is to understand tail calls, and to convert your program to accumulator style. And, at this point, I'm going to defer to the excellent discussion that appears in Alexis King's answer.
It looks like you are trying to calculate x!.
You defined factorial as a lambda with input x (here it is in a readable pseudocode, not a prefix syntax as in Scheme):
factorial (x) = {
(x=0) -> 1 // end condition
(x<>0) -> x * fact(x-1) // 'fact' should be 'factorial' AFAIK
}
or in other words:
factorial(x) * factorial(x-1) * factorial((x-1)-1) ...factorial(0) => x!
the following is already tail recursive ( a recursion were the last call is the recursion):
factorial (x , sum(1)) = {
(x=0) -> sum // end condition
(x<>0) -> fact(x-1 , sum(x*sum)) // 'fact' should be 'factorial' AFAIK
}
back to code, should be something like:
(define factorial
(lambda (x , sum=1)
(if (= x 0)
sum
(fact (- x 1) (* x sum)))))
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.
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.
The following Scheme code
(let ((x 1))
(define (f y) (+ x y))
(set! x 2)
(f 3) )
which evaluates to 5 instead of 4. It is surprising considering Scheme promotes static scoping. Allowing subsequent mutation to affect bindings in the closed environment in a closure seems to revert to kinda dynamic scoping. Any specific reason that it is allowed?
EDIT:
I realized the code above is less obvious to reveal the problem I am concerned. I put another code fragment below:
(define x 1)
(define (f y) (+ x y))
(set! x 2)
(f 3) ; evaluates to 5 instead of 4
There are two ideas you are confusing here: scoping and indirection through memory. Lexical scope guarantees you that the reference to x always points to the binding of x in the let binding.
This is not violated in your example. Conceptually, the let binding is actually creating a new location in memory (containing 1) and that location is the value bound to x. When the location is dereferenced, the program looks up the current value at that memory location. When you use set!, it sets the value in memory. Only parties that have access to the location bound to x (via lexical scope) can access or mutate the contents in memory.
In contrast, dynamic scope allows any code to change the value you're referring to in f, regardless of whether you gave access to the location bound to x. For example,
(define f
(let ([x 1])
(define (f y) (+ x y))
(set! x 2)
f))
(let ([x 3]) (f 3))
would return 6 in an imaginary Scheme with dynamic scope.
Allowing such mutation is excellent. It allows you to define objects with internal state, accessible only through pre-arranged means:
(define (adder n)
(let ((x n))
(lambda (y)
(cond ((pair? y) (set! x (car y)))
(else (+ x y))))))
(define f (adder 1))
(f 5) ; 6
(f (list 10))
(f 5) ; 15
There is no way to change that x except through the f function and its established protocols - precisely because of lexical scoping in Scheme.
The x variable refers to a memory cell in the internal environment frame belonging to that let in which the internal lambda is defined - thus returning the combination of lambda and its defining environment, otherwise known as "closure".
And if you do not provide the protocols for mutating this internal variable, nothing can change it, as it is internal and we've long left the defining scope:
(set! x 5) ; WRONG: "x", what "x"? it's inaccessible!
EDIT: your new code, which changes the meaning of your question completely, there's no problem there as well. It is like we are still inside that defining environment, so naturally the internal variable is still accessible.
More problematic is the following
(define x 1)
(define (f y) (+ x y))
(define x 4)
(f 5) ;?? it's 9.
I would expect the second define to not interfere with the first, but R5RS says define is like set! in the top-level.
Closures package their defining environments with them. Top-level environment is always accessible.
The variable x that f refers to, lives in the top-level environment, and hence is accessible from any code in the same scope. That is to say, any code.
No, it is not dynamic scoping. Note that your define here is an internal definition, accessible only to the code inside the let. In specific, f is not defined at the module level. So nothing has leaked out.
Internal definitions are internally implemented as letrec (R5RS) or letrec* (R6RS). So, it's treated the same (if using R6RS semantics) as:
(let ((x 1))
(letrec* ((f (lambda (y) (+ x y))))
(set! x 2)
(f 3)))
My answer is obvious, but I don't think that anyone else has touched upon it, so let me say it: yes, it's scary. What you're really observing here is that mutation makes it very hard to reason about what your program is going to do. Purely functional code--code with no mutation--always produces the same result when called with the same inputs. Code with state and mutation does not have this property. It may be that calling a function twice with the same inputs will produce separate results.