Why does Scheme allow mutation to closed environment in a closure? - scheme

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.

Related

Difference between usage of set! and define

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.).

Scheme/Guile: Variable self-re-definition inside a function

I feel that understanding this subtlety might help me to understand how scope works in Scheme.
So why does Scheme error out if you try to do something like:
(define (func n)
(define n (+ 1 n))
n)
It only errors out at runtime when calling the function.
The reason I find it strange is because Scheme does allow re-definitions, even inside functions. For example this gives no error and will always return the value 5 as expected:
(define (func n)
(define n 5)
n)
Additionally, Scheme also seems to support self-re-definition in global space. For instance:
(define a 5)
(define a (+ 1 a))
gives no error and results in "a" displaying "6" as expected.
So why does the same thing give a runtime error when it occurs inside a function (which does support re-definition)? In other words: Why does self-re-definition only not work when inside of a function?
global define
First off, top level programs are handled by a different part of the implementation than in a function and defining an already defined variable is not allowed.
(define a 10)
(define a 20) ; ERROR: duplicate definition for identifier
It might happen that it works in a REPL since it's common to redefine stuff, but when running programs this is absolutely forbidden. In R5RS and before what happened is underspecified and didn't care since be specification by violating it it no longer is a Scheme program and implementers are free to do whatever they want. The result is of course that a lot of underspecified stuff gets implementation specific behaviour which are not portable or stable.
Solution:
set! mutates bindings:
(define a 10)
(set! a 20)
define in a lambda (function, let, ...)
A define in a lambda is something completely different, handled by completely different parts of the implementation. It is handled by the macro/special form lambda so that it is rewritten to a letrec*
A letrec* or letrec is used for making functions recursive so the names need to be available at the time the expressions are evaluated. Because of that when you define n it has already shadowed the n you passed as argument. In addition from R6RS implementers are required to signal an error when a binding is evaluated that is not yet initialized and that is probably what happens. Before R6RS implementers were free to do whatever they wanted:
(define (func n)
(define n (+ n 1)) ; illegal since n hasn't got a value yet!
n)
This actually becomes:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn (+ n 1)))
(set! n tmpn))
n)))
Now a compiler might see that it violates the spec at compile time, but many implementations doesn't know before it runs.
(func 5) ; ==> 42
Perfectly fine result in R5RS if the implementers have good taste in books.
The difference in the version you said works is that this does not violate the rule of evaluating n before the body:
(define (func n)
(define n 5)
n)
becomes:
(define func
(lambda (n)
(let ((n 'undefined-blow-up-if-evaluated))
(let ((tmpn 5)) ; n is never evaluated here!
(set! n tmpn))
n)))
Solutions
Use a non conflicting name
(define (func n)
(define new-n (+ n 1))
new-n)
Use let. It does not have its own binding when the expression gets evaluated:
(define (func n)
(let ((n (+ n 1)))
n))

What is the purpose of Closures in Scheme/Racket?

I am learning Scheme and just came across Closures. The following example provided, demonstrating the use of Closures:
(define (create-closure x)
(lambda () x))
(define val (create-closure 10))
From what I understand, when the above code is evaluated, val will equal to 10. I realize this is just an example, but I don't understand just how a closure would be helpful. What are the advantages and what would a scenario where such a concept would be needed?
val is not 10 but a closure. If you call it like (val) it returns the value of x. x is a closure variable that still exists since it's still in use. A better example is this:
(define (larger-than-predicate n)
(lambda (v) (> v n )))
(filter (larger-than-predicate 5) '(1 2 3 4 5 6 7 8 9 10))
; ==> (6 7 8 9 10)
So the predicate compares the argument with v which is a variable that still holds 5. In a dynamic bound lisp this is not possible to do because n will not exist when the comparison happens.
Lecical scoping was introduces in Algol and Scheme. JavaScript, PHP amd C# are all algol dialects and have inherited it from there. Scheme was the first lisp to get it and Common Lisp followed. It's actually the most common scoping.
From this example you can see that the closure allows the functions local environment to remain accessible after being called.
(define count
(let ((next 0))
(lambda ()
(let ((v next))
(set! next (+ next 1))
v))))
(count)
(count)
(count)
0..1..2
I believe in the example you give, val will NOT equal to 10, instead, a lambda object (lambda () 10) will be assigned to val. So (val) equals to 10.
In the world of Scheme, there are two different concepts sharing the same term "closure". See this post for a brief introduction to both of these terms. In your case, I believe by "closure" you mean "lexical closure". In your code example, the parameter x is a free variable to the returned lambda and is referred to by that returned lambda, so a lexical closure is kept to store the value of x. I believe this post will give you a good explanation on what (lexical) closure is.
Totally agree with Lifu Huang's answer.
In addition, I'd like to highlight the most obvious use of closures, namely callbacks.
For instance, in JavaScript, I might write
function setup(){
var presses = 0;
function handleKeyPress(evt){
presses = presses + 1;
return mainHandler(evt);
}
installKeyHandler(handleKeyPress);
}
In this case, it's important to me that the function that I'm installing as the key handler "knows about" the binding for the presses variable. That binding is stored in the closure. Put differently, the function is "closed over" the binding for presses.
Similar things occur in nearly every http GET or POST call made in JS. It crops up in many many other places as well.
Btw, create-closure from your question is known by some as the Kestrel combinator, from the family of Combinator Birds. It is also known as True in Church encoding, which encodes booleans (and everything else) using lambdas (closures).
(define (kestrel a)
(lambda (b) a))
(define (create-list size proc)
(let loop ((x 0))
(if (= x size)
empty
(cons (proc x)
(loop (add1 x))))))
(create-list 5 identity)
; '(0 1 2 3 4)
(create-list 5 (kestrel 'a))
; '(a a a a a)
In Racket (I'm unsure about Scheme), this procedure is known as const -
(create-list 5 (const 'a))
; '(a a a a a)

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.

Scheme: append to local environment

Say, I want to implement "declarative" object system in Scheme by defining object symbol and then appending methods and fields to that object. While doing so, I want to exploit the local environment of this object to properly bind it's fields in methods (which are added later), for instance (a very "hacked-together" example):
(define myobj
(begin
(define x 5) ; some local field (hard-coded for example)
(define (dispatch m d)
(cond ((eq? m 'add-meth) (define localmethod1 d))
((eq? m 'inv-meth) (localmethod1 d))))
dispatch
))
(myobj 'add-meth (lambda (y) (+ y x)) ;want this to bind to x of myobj
(myobj 'inv-meth 3) ;8
Don't mind silly dispatching mechanism and hard-coded "localmethod1" :) Also do mind, that x may not be available during definition of dispatcher.
First of all, I get problems with using define in define (Bad define placement).
Then: how to make sure that x in lambda binds to the right one (inside of myobj) and not to some x in global environment?
Last: Is there a way to mutate such local enivornments (closures, right?) at all?
EDIT2: I know that you can make this with local lists like "fields" and "methods" and then mutate those by a dispatcher. I wanted to know if there is a possibility of mutating local environment (produced by a dispatch lambda).
begin in Scheme does not produce local environment. To introduce local variables use let. Or, alternatively define an object, or rather a class to construct the object, as lambda-procedure, that will act as a constructor. This will solve your first two problems.
To mutate: you can mutate by having a right dispatch method. For example,
(define (make-object init-val)
(define x init-val)
(define (dispatch msg)
(cond ((eq? msg 'inc)
(lambda (y)
(set! x (+ x y))))
((eq? msg 'x)
x)
(else
(error "Unknown msg"))))
dispatch)
> (define obj (make-object 10))
> (obj 'x)
10
> ((obj 'inc) 20)
> (obj 'x)
30
SICP, Chapter 3 provides good examples of how to make objects with local state.
You are saying:
x may not be available during definition of dispatcher
and then you are asking:
Then: how to make sure that x in lambda binds to the right one (inside of myobj) and not to some x in global environment?
The short answer is: you can't.
The reason is that (see for instance the Mit-Scheme manual):
Scheme is a statically scoped language with block structure. In this respect, it is like Algol and Pascal, and unlike most other dialects of Lisp except for Common Lisp.
The fact that Scheme is statically scoped (rather than dynamically bound) means that the environment that is extended (and becomes current) when a procedure is called is the environment in which the procedure was created (i.e. in which the procedure's defining lambda expression was evaluated), not the environment in which the procedure is called. Because all the other Scheme binding expressions can be expressed in terms of procedures, this determines how all bindings behave.
(emphasis mine)

Resources