For every 100% compliant R7RS-small program that does not rely on any implementation-specific or undefined behavior, is it true that every instance of letrec in the program can be replaced with letrec* without causing any change in behavior? In other words, is there any R7RS-small program where an appearance of letrec cannot be substituted with letrec*?
I think that the answer is yes, it can, assuming that the form is not 'an error' in R7RS terminology (but see note at end). In particular I think that if there's a form like
(letrec ((v1 <e1>) (v2 <e2>)) ...)
Then it must be possible to evaluate <e2> without referring to the value of v1, but that binding does actually exist when <e2> is evaluated: it is just an error to refer to it. So in particular this is not allowed:
(let ((a 1)) (letrec ((a 2) (b a)) ...))
because the binding that the init for b refers to is that established by the letrec, not that established by the let, but it is not yet legal to refer to the value of that binding.
That being the case then if you simply replace letrec by letrec* then <e2> still will not refer to the value of v1 and thus the results will be the same.
The converse is not true:
(letrec* ((a 1) (b a)) ...)
is fine, but you can't replace the letrec* by letrec there.
That being the case I'm unclear what useful purpose letrec serves (perhaps this is why Racket's letrec has the semantics of Scheme's letrec*).
Note an earlier version of this answer came to the opposite conclusion. I am now not convinced I understand things well enough.
Related
I tried to evaluate this: (define lambda (lambda (x) x)). MIT Scheme 11.2 gives an error: ;Unbound variable: x. Chez Scheme 9.5 also gives an error: Exception: variable x is not bound. Why is x not bound? I thought that define would evaluate (lambda (x) x) into an anonymous function, and then define lambda to be that anonymous function. Where does x get involved?
I don't get any errors in Racket 7.2 and Guile 3.0.1.
This isn't valid Scheme code:
(define lambda (lambda (x) x))
R7RS seems pretty clear about forbidding this in Section 5.4 about syntax definitions:
However, it is an error for a definition to define an identifier whose binding has to be known in order to determine the meaning of the definition itself, or of any preceding definition that belongs to the same group of internal definitions.
In the posted code the identifer lambda is being redefined, but the binding of lambda itself must be known in order to determine the meaning of the new definition; the above language forbids this.
R6RS has some similar language in Chapter 10 about the expansion process, but the R6RS language is more tightly coupled to the technical details of the expansion process. I'm pretty sure that it applies in the same way to this case, but not 100% sure.
A definition in the sequence of forms must not define any identifier whose binding is used to determine the meaning of the undeferred portions of the definition or any definition that precedes it in the sequence of forms.
OP notes the error message Exception: variable x is not bound and asks: "Where does x get involved?"
Granting that (define lambda (lambda (x) x)) is malformed and thus not valid Scheme, it isn't too meaningful to try to explain such behaviors. Yet it seems that this sort of behavior can be triggered by attempting to redefine other syntactic keywords in similar fashion. Consider:
> (define if (if x y z))
Exception: variable z is not bound
It seems obvious here that z is unbound, so the error doesn't seem unreasonable. But now:
> (define if (if #t 1 2))
Exception: variable if is not bound
Even if is unbound in the right-hand expression of the define form! If we assume that something similar is happening in (define lambda (lambda (x) x)) then lambda is unbound in the right-hand expression, and if that is the case, then (lambda (x) x) is not evaluated as a special form, but as an ordinary procedure call. The order of evaluation for arguments in a procedure call is unspecified, so it is perfectly reasonable that x could be reported as unbound before lambda in this case. We can get rid of the appearances of unbound xs to see if lambda is being bound:
> (define lambda (lambda))
Exception: variable lambda is not bound
> (define lambda lambda)
Exception: variable lambda is not bound
So it seems that the problem here is that attempting to redefine a syntactic keyword using an expression that relies on that keyword for its meaning can cause the binding for the syntactic keyword to become inaccessible.
In any case, take this last bit with a grain of salt because in the end this sort of redefinition is not valid code, and no particular behavior should be expected of it.
I am still having some troubles with this concept. The key paragraph in the r7rs standard is:
"Identifiers that appear in the template but are not pattern
variables or the identifier ellipsis are inserted into the output as literal identifiers. If a literal identifier is inserted as a
free identifier then it refers to the binding of that identifier
within whose scope the instance of syntax-rules appears.
If a literal identifier is inserted as a bound identifier then
it is in effect renamed to prevent inadvertent captures of
free identifiers."
By "bound identifier" am I right that it means any argument to a lambda, a top-level define or a syntax definition ie. define-syntax, let-syntax or let-rec-syntax? (I think I could handle internal defines with a trick at compile time converting them to lambdas.)
By "free identifier" does it mean any other identifier that presumably is defined beforehand with a "bound identifier" expression?
I wonder about the output of code like this:
(define x 42)
(define-syntax double syntax-rules ()
((_) ((lambda () (+ x x)))))
(set! x 3)
(double)
Should the result be 84 or 6?
What about this:
(define x 42)
(define-syntax double syntax-rules ()
((_) ((lambda () (+ x x)))))
(define (proc)
(define x 3)
(double))
(proc)
Am I right to suppose that since define-syntax occurs at top-level, all its free references refer to top-level variables that may or may not exist at the point of definition. So to avoid collisions with local variables at the point of use, we should rename the outputted free reference, say append a '%' to the name (and disallow the user to create symbols with % in them). As well as duplicate the reference to the top-level variable, this time with the % added.
If a macro is defined in some form of nested scope (with let-syntax or let-rec-syntax) this is even trickier if it refers to scoped variables. When there is a use of the macro it will have to expand these references to their form at point of definition of the macro rather than point of use. So I'm guessing the best way is expand it naturally and scan the result for lambdas, if it finds one, rename its arguments at point of definition, as the r7rs suggests. But what about references internal to this lambda, should we change these as well? This seems obvious but was not explicitly stated in the standard.
Also I'm still not sure whether it is best to have a separate expansion phase separate from the compiler, or to interweave expanding macros with compiling code.
Thanks, and excuse me if I've missed something obviously, relatively new to this.
Steve
In your first example, properly written:
(define x 42)
(define-syntax double
(syntax-rules ()
( (_) ((lambda () (+ x x))) ) ))
(set! x 3)
(double)
the only possibility is 6 as there is only one variable called x.
In your second example, properly written:
(define x 42)
(define-syntax double
(syntax-rules ()
((_) ((lambda () (+ x x))) )))
(define (proc)
(define x 3)
(double))
(proc)
the hygienic nature of the Scheme macro system prevents capture of the unrelated local x, so the result is 84.
In general, identifiers (like your x) within syntax-rules refer to what they lexically refer to (the global x in your case). And that binding will be preserved because of hygiene. Because of hygiene you do not have to worry about unintended capture.
Thanks, I think I understand... I still wonder how in certain advanced circumstances hygiene is achieved, eg. the following:
(define (myproc x)
(let-syntax ((double (syntax-rules ()
((double) (+ x x)))))
((lambda (x) (double)) 3)))
(myproc 42)
The site comes up with 84 rather than 6. I wonder how this (correct) referential transparency is achieved just by renaming. The transformer output does not bind new variables, yet still when it expands on line 4, we have to find a way to get to the desired x rather than the most recent.
The best way I can think of is simply rename every time a lambda argument or definition shadows another, ie. keep appending %1, %2 etc... macro outputs will have their exact versions named (eg. x%1) while references to identifiers simply have their unadorned name x and the correct variable is found at compile time.
Thanks, I hope for any clarification.
Steve
I'm looking for the closest equivalent (both typographically and semantically) to what the following would do if functions in Elisp were "first-class":
(let ((f function-with-very-long-name))
(progn
...
(f ...) ;; evaluates to (function-with-very-long-name ...)
...
)
)
IOW, I'm looking for a convenient way to define lexically scoped aliases for functions.
The closest I've found involves binding the aliasing symbol (f in the example above) to a lambda that in turn calls the aliased function. I find this approach typographically cumbersome. (It negates whatever typographic simplification the rest of the code may have gained from the aliasing.)
Is there anything better?
I think the simplest way is to use cl-flet or cl-labels (the exact names may depend on which version of Emacs you are using, due to the great cl-* renaming. You can also use cl-letf with (symbol-function 'symbol) if you prefer, though I think that's needlessly obscure.
You can use funcall for this. For example, the let below passes 21 to a-function-with-an-extremely-long-name, which doubles it and returns 42:
(defun a-function-with-an-extremely-long-name (i) (* 2 i))
(let ((f 'a-function-with-an-extremely-long-name))
(funcall f 21))
Why is it that:
Function definitions can use definitions defined after it
while variable definitions can't.
For example,
a) the following code snippet is wrong:
; Must define function `f` before variable `a`.
#lang racket
(define a (f))
(define (f) 10)
b) While the following snippet is right:
; Function `g` could be defined after function `f`.
#lang racket
(define (f) (g)) ; `g` is not defined yet
(define (g) 10)
c) Right too :
; Variable `a` could be defined after function `f`
#lang racket
(define (f) a) ; `a` is not defined yet
(define a 10)
You need to know several things about Racket:
In Racket, each file (that starts with #lang) is a module, unlike many (traditional, r5rs) schemes that have no modules.
The scoping rules for modules are similar to the rules for a function, so in a sense, these definitions are similar to definitions in a function.
Racket evaluates definitions from left to right. In scheme lingo you say that Racket's definitions have letrec* semantics; this is unlike some schemes that use letrec semantics where mutually recursive definitions never work.
So the bottom line is that the definitions are all created in the module's environment (similarly in a function, for function-local definitions), and then they are initialized from left to right. Back-references therefore always work, so you can always do something like
(define a 1)
(define b (add1 a))
They are created in a single scope -- so in theory forward definitions are valid in the sense that they're in scope. But actually using a value of a forward-reference is not going to work since you get a special #<undefined> value until the actual value is evaluated. To see this, try to run this code:
#lang racket
(define (foo)
(define a a)
a)
(foo)
A module's toplevel is further restricted so that such references are actually errors, which you can see with:
#lang racket
(define a a)
Having all that in mind, things are a bit more lenient with references inside functions. The thing is that the body of a function is not executed until the function is called -- so if a forward reference happens inside a function, it is valid (= won't get an error or #<undefined>) if the function is called after all of the bindings have been initialized. This applies to plain function definitions
(define foo (lambda () a))
definitions that use the usual syntactic sugar
(define (foo) a)
and even other forms that ultimately expand into functions
(define foo (delay a))
With all of these, you won't get any errors by the same rule -- when all uses of the function bodies happen after the definitions were initialized.
One important note, however, is that you shouldn't confuse this kind of initialization with assignment. This means that things like
(define x (+ x 1))
are not equivalent to x = x+1 in mainstream languages. They're more like some var x = x+1 in a language that will fail with some "reference to uninitialized variable" error. This is because define creates a new binding in the current scope, it does not "modify" an existing one.
The following is an approximate general Scheme description, an analogy.
Defining a function
(define (f) (g))
is more or less like
f := (lambda () (g))
so the lambda expression is evaluated, and the resulting functional object (usually a closure) is stored in the new variable f being defined. The function g will have to be defined when the function f will be called.
Similarly, (define (h) a) is like h := (lambda () a) so only when the function h will be called, the reference to the variable a will be checked, to find its value.
But
(define a (f))
is like
a := (f)
i.e. the function f has to be called with no arguments, and the result of that call stored in the new variable a being defined. So the function has to be defined already, at that point.
Each definition in a file is executed in sequence, one after another. Each definition is allowed to refer to any of the variables being defined in a file, both above and below it (they are all said to belong to the same scope), but it is allowed to use values of only those variables that are defined above it.
(there is an ambiguity here: imagine you were using a built-in function, say with (define a (+ 1 2)), but were also defining it later on in the file, say (define + -). Is it a definition, or a redefinition? In the first case, which is Racket's choice, use before definition is forbidden. In the second, the "global" value is used in calculating the value of a, and then the function is redefined. Some Schemes may go that route. Thanks go to Eli Barzilay for showing this to me, and to Chris Jester-Young for helping out).
What 'kind of thing' will I get if I do this?
(car (list lambda lambda))
I thought I'd get lambda back, which means I could do
(define my_lambda (car (list lambda lambda)))
(define foo (my_lambda (n) (+ n n)))
But that didn't work!
Thanks,
lambda is a special form (meaning: standard evaluation rules don't apply to it), part of the core primitives of the language and is not a symbol or other kind of value that can be assigned to a variable.
Answering your question, the "kind of thing" that you'll get after evaluating the expression (list lambda) will depend on the Scheme interpreter that you're using, but more often than not you'll get an error. For instance, DrRacket complains like this:
lambda: bad syntax in: lambda
In some sense, lambda doesn't exist at runtime (sure, the functions created by lambda statements exist, but that's a different matter; they aren't lambda itself).
The reason for this is that the lambda statement manipulates other things that don't exist at runtime; in particular, it changes the meaning of variable names (in your example, n).
To answer your question about what kind of thing lambda is, the usual answer is "syntax". Fortunately, Scheme provides a mechanism to abstract over syntax: macros. Macros can abstract over compile-time-only entities, like variable names and lambdas and other macros. So, you could write (in the Racket REPL, in this case):
> (define-syntax-rule (mylambda (x ...) body)
(lambda (x ...) body))
> (define foo (mylambda (n) (+ n n)))
> (foo 71)
142
There are multiple systems for defining Scheme macros; the syntax-rules system uses ...s in an unusual, but ultimately pretty intuitive fashion. It is also possible to define macros by writing Scheme code that emits Scheme, which involves a little more complication.