lexical scoping in scheme - scheme

I am trying to understand concepts of lexical and dynamic scoping and the differences between them.
Let's take a look at the following code:
(let ((a 1)
(b 2))
(letrec ((f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
For expressions F and G, which variables are at lexical scope of (lambda(d)...)?

(lambda(d)...) has d as bound variable and f, g a b and all of the global scope as free variables.
EDIT
Just to demonstrate the code in Scheme and some other language where the same bindings are dynamic. Since neither of your functions call each other you might as well keep them in the same let:
(define test
(let ((a 1)
(b 2)
(f (lambda () F))
(g (lambda (c) G)))
(lambda (d)
(+ (f) (g b)))))
;; for the test we need the F and G defined
(define F 10)
(define G 20)
(test 4) ; ==> 30 (aka (+ F G))
What happens is that when the lambda gets evaluated the variables it uses from the lexical scope lives on even after the let is gone. In a dymaic scope this isn't true:
(test 4)
; ERROR f: unbound identifier
The reason for this is while a, b, f and g existed when the lamba was evaluated none of the variables get captured like in lexical scope and thus when the procedure test is made none of the local variables exist anymore. In fact you might as well write it like this:
;; in a dynamic lisp this s the same
(define test
(lambda (d)
(+ (f) (g b))))
And you must make sure the variable exist when you call the function (aka dynamic)
(define g (lambda (v) 1337))
(define f (lambda () 3.1415927))
(define b 13)
(test 4) ; ==> 1340.1415927
Now if you were to add the above definitions in the global scope and keep the original definition you'd still get 30 since a lexical lisp uses the closer lexical bindings rather than the global ones.
Another great example is this:
(define x 10)
(define (test v)
(+ x v))
(let ((x 20))
(test 10))
; ==> ?
In a lexical lisp the result would be always 20 since test does not have any idea of the let since it is not in its lexical scope. It's x is always the global bindings x. In a dymamic lisp the x from the let is the closest one from the runtime point of view which would result in 30 since the x in test is the same as the x in the let and it shadows the global x.

Related

What Scheme special forms must the hygienic macro expander know about?

syntax-rules in Scheme are "hygienic" and "referentially transparent" and must preserve Scheme's lexical scoping. From my understanding, this means that during the macro expansion phase, the expander would need to know about lambda and define.
The expander needs to know about lambda.
Suppose we have this code:
(define x 1)
((lambda (x) x) 2)
If the expander did not know about the lambda special form, it would consider the two xs in (lambda (x) x) to be bound to the x in (define x 1), which is incorrect.
The expander needs to know about define, so that it knows where (i.e. in which scope) a particular identifier is defined. In addition, suppose we have this code:
(define n 1)
(define f (lambda (x y) (+ x y)))
(define lambda f)
(lambda n n)
In order to correctly determine that both n in (lambda n n) refer to (define n 1), the expander has to understand that (define lambda f) has changed the meaning of lambda (and therefore the expander has to stop using special rules for handling lmabda in this scope).
What other special forms does the macro expander need to know about? Does it need to know about set!?
The examples seem to be about lexical scoping, not macro expansion.
(define x 1)
((lambda (x) x) 2)
The binding of x in the second line shadows that in the first.
Similarly in the second example (define lambda f) binds lambda
in the region following the define; there is no macro expansion.
The identifier lambda can be used as a keyword in a syntactic extension (macro);
lexical scoping applies normally, there are no special rules:
> (let-syntax ([lambda (syntax-rules ()
[(lambda arg) ((lambda (x) (+ 1 x)) arg)])])
(lambda 2))
3
>
But:
> (letrec-syntax ([lambda (syntax-rules ()
[(lambda arg) ((lambda (x) (+ 1 x)) arg)])])
(lambda 2))
Exception: invalid syntax (lambda (x) (+ 1 x))
>

When to use define and when to use let in racket

I'm learning racket and I have a question about when to use define and when to use let.
I have this function:
(define my-function
(lambda (param1 param2 list1)
(/
(count
(lambda (x)
(define a (param1 (remove x list1)))
(define b (drop-right x 1))
(define c (param2 a x-sin-clase))
(eq? (last x) (last c)))
(cdr list1))
(length (cdr list1)))))
Without knowing what the above function does. Is it correct to use define inside the function body?
I have read somewhere that define is used to declare global variables and let is used to declare local variables. I've look in racket's documentation but it doesn't talk about any difference.
One difference: Internal defines are in a mutually recursive scope, but let bindings are not.
This means than in a let:
(let ([x expr-1] [y expr-2])
body)
The expr-1 and expr-2 cannot refer to x or y. More concretely,
(let ([x (stream-cons 1 y)] [y (stream-cons 2 x)])
x)
;error=> y: unbound identifier in: y
And if x or y is defined outside of the let, expr-1 and expr-2 will refer to the outer definitions, and not the ones introduced by the let. Concretely:
(define x 'outer)
(let ([x 'inner] [y x]) ; <- this x refers to outer,
y) ; so y is 'outer
;=> 'outer
However, internal defines have a mutually recursive scope, which means that in
(block
(define x expr-1)
(define y expr-2)
body)
The expr-1 and expr-2 can refer to x or y. Concretely,
(require racket/block)
(block
(define x (stream-cons 1 y))
(define y (stream-cons 2 x))
(stream->list (stream-take x 5)))
;=> (list 1 2 1 2 1)
The Scope of a define
....A....
(define (f)
(define t1 ..B..)
(define x ..C..)
(define t2 ..D..)
....E....)
....F....
The x is visible everywhere in the body of f, but not outside that. That means it's visible in B, C, D, and E, but not in A or F.
The Scope of a let
....A....
(define (f)
(let ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Here the x is visible everywhere in the body of the let, but not outside that. That means it's visible in E, but not in A, B, C, D, or F.
The Scope of a let*
....A....
(define (f)
(let* ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
Here the x is visible everywhere in the body of the let* and in let* bindings that come after it, but not outside that. That means it's visible in D and E, but not in A, B, C, or F.
The Scope of a letrec
....A....
(define (f)
(letrec ([t1 ..B..]
[x ..C..]
[t2 ..D..])
....E....))
....F....
The x is visible everywhere in the body of the letrec and in the bindings of the letrec, but not outside that. That means it's visible in B, C, D, and E, but not in A or F.
The scope of variables in letrec and the scope of local define variables are very similar because both letrec and define work with mutually recursive scopes.
I've finally understood what I have read that define's variable are "global variables".
In the book The Scheme Programming Language Fourth Edition, R. Kent Dybvig, section 2.6. Top Level Definitions says:
The variables bound by let and lambda expressions are not visible
outside the bodies of these expressions.

dynamic scope returns undefined var

The code below, under dynamic scope assumption, would return error.
(let ((f (lambda (g)
(lambda (n)
(if (zero? n)
1
(* n ((g g) (- n 1))))))))
((f f) 5))
My answer was 0, because:
n*(n-1)*(n-2)*(n-3)*(n-3)*(n-4)*1;; since the call with n=0, n bound to 0
0*0*0*0*1
What am I missing here?
(define test
(let ((x 10))
(lambda () x)))
Here we return lambda function from the scope where x is a local variable. Under lexical scope an environment gets attached to the created lambda function. This environment consists of the bound variables on top of the free variables that were available when the lambda function was being created -- here, x, bound to 10. Thus when this returned lambda function is called, its x can only be 10.
In dynamic scope the let is dead code. The lambda function that is created does not store its lexical environment and thus when it will be called, x will be looked up fresh, at the actual time of the call. The variable that was called x with value 10 will no longer exist by then. The x looked up by the lambda will be whatever you have x bound to, at the call time:
(let ((x 20))
(test))
; ==> 20
And of course:
(test); == ERROR: Unbound variable x
So to your code it's the same problem. Whatever g is when (lambda (n) ...) is evaluated, creating the lambda function, goes out of scope when that lambda function is returned, and thus when that returned lambda function is called, g will be looked up fresh, and will be whatever g is bound to at the time of calling, as before. In order for this to work in a dynamic scope you could do this:
(let ((f (lambda (g n)
(if (zero? n)
1
(* n (g g (- n 1)))))))
(f f 5))
The difference here is that g never goes out of scope. This works in both dynamic and lexical scope. You can simplify it for dynamic scope like this:
(let ((f (lambda (n) ; ((lambda (f) (f 5))
(if (zero? n) ; (lambda (n)
1 ; (if (zero? n)
(* n (f (- n 1))))))) ; 1
(f 5)) ; (* n (f (- n 1))))))
In lexical scope the f inside (lambda (n) ...) is unbound variable, but in a dynamic scope f is first established, and after the call (f 5) it remains available for all the nested calls, (f 4), (f 3) etc., until the evaluation of (f 5) inside (lambda (f) (f 5)) is finished; only then that f is disestablished, destroyed, when that lambda is exited returning the result of (f 5).
In Paul Grahams nice wrap-up of McCarthys original lisp paper he mentions that there was a bug in the paper. The very first higher order function, maplist, had x as the name for the list argument. In the demonstration diff he passes a function to maplist that has x as a parameter. These two collide after the first pair and thus it does not work because of dynamic scope. Dynamic scope is extremely error prone and in Common Lisp where all globals are dynamic, the *earmuffs* naming convention is a necessity to avoid countless hours finding the global that changed the function to do something completely different than expected.
Using dynamic scope, g will be undefined because there is no variable named g on line 6.

Scheme Scoping (define and let)

So I know that in Scheme define is for dynamic scoping and let for static scoping, yet the following thing confuses me:
If I have
(let ((x 0))
(define f (lambda () x))
(display (f))
(let ((x 1))
(display (f))
)
)
It will display 00. So far so good. However, if I add an extra define for x like so:
(let ((x 0))
(define f (lambda () x))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
It will display undefined4. Why is this? Why does defining x after evaluating f affect the returned value of (f)? And why is the return value "undefined"?
It is also worth mentioning that binding f with letrec instead of define will also work:
(let ((x 0))
(letrec ((f (lambda () x)))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
)
Returns 00.
Note: I have used DrRacket with the languge set on "Pretty Big"
The issue you're experiencing in the second case is that (define x 42) makes x a variable for the entire scope in which it's defined. Now, although the variable is defined for the entire scope, its value is undefined until the actual (define x 42) line.
(let ()
;; up here, `x` is defined but has an undefined value
;; ...
(define x 42)
;; down here `x` has the value 42
;; ...
)
It's acting more like this:
(let ([x 'undefined])
;; ... up here, `x` is 'undefined
(set! x 42)
;; ... down here, `x` is 42
)
Your second and third code snippets are not Scheme (none of R5RS, R6RS nor R7RS). The <body> (of a let and others) is defined as:
<body> -> <definition>* <sequence>
<sequence> -> <command>* <expression>
<command> -> <expression>
and thus a define (which is a <definition>) cannot follow display (an <expression>). You are likely getting confusing results because the compiler/interpreter is incorrectly handling the expansion of 'let'.
Here is what a 'good' R6RS compiler does:
> (let ((x 0))
(letrec ((f (lambda () x)))
(display (f))
(define x 4)
(let ((x 1))
(display (f))
)
)
)
Unhandled exception
Condition components:
1. &who: define
2. &message: "a definition was found where an expression was expected"
3. &syntax:
form: (define x 4)
subform: #f
4. &trace: #<syntax (define x 4)>
>
Case 1: the body of f binds to the outermost let in both invocations, resulting in 00 as static scope requires.
Case 2: I'm not very sure about this, but the internal (define x 4) shadows the outermost x=0 binding, and is in scope throughout even though it's textually after the call to f. Then some order of evaluation trickiness makes the first call happen before the new x binding is fully initialized, so it's "uninitialized". The second call in the inner let happens after everything is initialized, so 4.
Case 3: Now that we have explicitly put the letrec and the define in separate scopes, f obviously refers to the outermost let. The define does nothing here.

Using let in Scheme

I want to write a program to find the roots of the quadratic equation in Scheme. I used LET for certain bindings.
(define roots-with-let
(λ (a b c)
(let ((4ac (* 4 a c))
(2a (* 2 a))
(discriminant (sqrt ( - (* b b) (4ac)))))
(cons ( / ( + (- b) discriminant) 2a)
( / ( - (- b) discriminant) 2a)))))
I defined the discriminant with 4ac since I did not want (* 4 a c). Even though I have defined (4ac (* 4 a c)), it is giving me this error:
expand: unbound identifier in module in: 4ac.
My question is how is let evaluated (what order)? And if i want 4ac in my let should i write another inner let? Is there a better way to do this?
Use let* instead of let.
The difference between let and let* is the following:
let* binds variables from left to right. Earlier bindings can be used in new binding further to the right (or down).
let on the other hand can be thought of as syntactic sugar (or macro) for simple lambda abstraction:
(let ((a exp1)
(b exp2))
exp)
is equivalent to
((lambda (a b)
exp)
exp1 exp2)
4ac is a variable with a numeric value, so (4ac) is not meaningful.
LET binds all variables, but the variables can't be used in the computations for the values.
This does not work:
(let ((a 1) (b 1) (c (* a b)))
c)
Use:
(let ((a 1) (b 1))
(let ((c (* a b)))
c))
Above introduces A and B with the first LET. In the second LET both A and B now can be used to compute C.
Or:
(let* ((a 1) (b 1) (c (* a b)))
c)
You'll need a special let-construct (let*) here since the variables inside the let-definition refer to each other.
It's rather a problem of defining a scope than of evaluating an expression (In usual let-definitions, the order of evaluation doesn't matter since the values may not use each other)
When you use let, the bindings are not visible in any of the bodies. Use let* instead and see the RNRS docs for details.

Resources