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

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

Related

Function evaluating to lambda cannot be used to define new function within scope

In scheme you can define functions which return a lambda expression and use them to define new functions. For example, you can write this code
(define (pow-iter base exp r)
(if (= exp 1)
r
(pow-iter base (- exp 1) (* base r))))
(define (pow exp)
(lambda (base)
(pow-iter base exp base)))
(define cubic (pow 3))
(cubic 2)
We have here a function pow which takes the exponent as argument and evaluates to a lambda function which evaluates to the nth power of the given base.
However, if we put that within a scope like this:
(define (do-cubic x)
(define (pow-iter base exp r)
(if (= exp 1)
r
(pow-iter base (- exp 1) (* base r))))
(define (pow exp)
(lambda (base)
(pow-iter base exp base)))
(define cubic (pow 3))
(cubic x))
(do-cubic 2)
I get an error
pow: undefined; cannot use before initialization
Why does this error occur and is there any way to fix it without changing the logic of the program?
This program provokes the same error:
#lang r5rs
(let ()
(define (foo x) (lambda (y) (+ 42 x)))
(define bar (foo 1))
(bar 2))
Output:
foo: undefined;
cannot use before initialization
The reason you get an error is that "internal definitions" are rewritten into a letrec expression all the bindings are in effect while their initial values are being computed, thus allowing mutually recursive definitions.
(letrec ((foo (lambda (x) (lambda (y) (+ 42 x))))
(bar (foo 1)))
(bar 2))
In R5RS the initialization expressions are evaluated in an unspecified order. This means that in the first snippet above it is possible for (define bar (foo 1)) to be evaluated before (define (foo x) ...). In other words the value of foo is needed before foo have been initialized.
In Racket (#lang racket) internal definitions use letrec*-semantics (i.e. the initialization expressions are evaluated in the order they appear in the code. Thus the program runs without errors.
Note also that the letrec in #lang racket corresponds to what letrec* does in "R5RS"-implementations.
For more information on letrec vs letrec* see the introduction of http://www.cs.indiana.edu/~dyb/pubs/letrec-reloaded.pdf

Scheme letrec infinite environment

I'm currently writing metacircular evaluator in Scheme, following the SICP book's steps.
In the exercise I am asked to implement letrec, which I do in the following way:
(define (letrec->let exp)
(define (make-unassigned var)
(list var '*unassigned*))
(define (make-assign binding)
(list 'set! (letrec-binding-var binding)
(letrec-binding-val binding)))
(let ((orig-bindings (letrec-bindings exp)))
(make-let
(map make-unassigned
(map letrec-binding-var orig-bindings))
(sequence->exp
(append
(map make-assign orig-bindings)
(letrec-body exp))))))
However, when I evaluate the expression as follows, it goes into infinite loop:
(letrec
((a (lambda () 1)))
(+ 1 (a)))
Do I miss anything?
(Full Source Code at GitHub).
I checked result transformation result of (let ((x 1)) x) and got:
((lambda (x) (x)) 1)
instead of:
((lambda (x) x) 1)
obviously problem is in let body processing. If I were you, I would use utility function:
(define (implicit-begin exps)
(if (= 1 (length x))
(car x)
(cons 'begin x)))
By the way: I would say, that your letrec implementation is not very correct. Your transformation returns:
(let ((x1 *unassigned*>) ... (xn *unassigned*))
(set! x1 ...)
...
(set! xn ...)
body)
It much more resembles letrec* which evaluates expressions for variable bindings in left-ro-right order (Scheme itself doesn't specify arguments evaluation order):
syntax: letrec* bindings body
Similar to ‘letrec’, except the INIT expressions are bound to their
variables in order.
‘letrec*’ thus relaxes the letrec restriction, in that later INIT
expressions may refer to the values of previously bound variables.
The more correct code would be:
(let ((x1 *unassigned*) ... (xn *unassigned*))
(let ((t1 ...) ... (tn ...))
(set! x1 t1)
...
(set! xn tn))
body)

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.

Which is the current continuation in the following expression?

In the expression (call/cc (lambda (k) (k 12))), there are three continuations: (k 12), (lambda (k) (k 12)), and (call/cc (lambda (k) (k 12))). Which one is the "current continuation"?
And continuations in some books are viewed as a procedure which is waiting for a value and it will return immediately when it's applied to a value. Is that right?
Can anyone explain what current continuations are in detail?
Things like (k 12) are not continuations. There is a continuation associated with each subexpression in some larger program. So for example, the continuation of x in (* 3 (+ x 42)) is (lambda (_) (* 3 (+ _ 42))).
In your example, the "current continuation" of (call/cc (lambda (k) (k 12))) would be whatever is surrounding that expression. If you just typed it into a scheme prompt, there is nothing surrounding it, so the "current continuation" is simply (lambda (_) _). If you typed something like (* 3 (+ (call/cc (lambda (k) (k 12))) 42)), then the continuation is (lambda (_) (* 3 (+ _ 42))).
Note that the lambdas I used to represent the "current continuation" are not the same as what call/cc passes in (named k in your example). k has a special control effect of aborting the rest of the computation after evaluating the current continuation.
The continuation in this case is the "thing" that receives the return value of the call/cc invocation. Thus:
(display (call/cc (lambda (k) (k 12)))
has the same result as
(display 12)
Continuations in Scheme "look and feel" like procedures, but they do not actually behave like procedures. One thing that can help you understand continuations better is CPS transformations.
In CPS transformation, instead of a function returning a value, instead it takes a continuation parameter, and invokes the continuation with the result. So, a CPS-transformed sqrt function would be invoked with (sqrt 64 k) and rather than returning 8, it just invokes (k 8) in tail position.
Because continuations (in a CPS-transformed function) are tail-called, the function doesn't have to worry about the continuation returning, and in fact, in most cases, they are not expected to return.
With this in mind, here's a simple example of a function:
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
and its CPS-transformed version:
(define (hypot x y k)
(* x x (lambda (x2)
(* y y (lambda (y2)
(+ x2 y2 (lambda (sum)
(sqrt sum k))))))))
(assuming that *, +, and sqrt have all been CPS-transformed also, to accept a continuation argument).
So now, the interesting part: a CPS-transformed call/cc has the following definition:
(define (call/cc fn k)
(fn k k))
With CPS transformation, call/cc is easy to understand and easy to implement. Without CPS transformation, call/cc is likely to require a highly magical implementation (e.g., via stack copying, etc.).

Anonymous lambdas directly referring to themselves

Does Scheme or do any dialects of scheme have a kind of "self" operator so that anonymous lambdas can recur on themselves without doing something like a Y-combinator or being named in a letrec etc.
Something like:
(lambda (n)
(cond
((= n 0) 1)
(else (* n (self (- n 1)))))))
No. The trouble with the "current lambda" approach is that Scheme has many hidden lambdas. For example:
All the let forms (including let*, letrec, and named let)
do (which expands to a named let)
delay, lazy, receive, etc.
To require the programmer to know what the innermost lambda is would break encapsulation, in that you'd have to know where all the hidden lambdas are, and macro writers can no longer use lambdas as a way to create a new scope.
All-round lose, if you ask me.
There is a tradition of writing “anaphoric” macros that define special names in the lexical scope of their bodies. Using syntax-case, you can write such a macro on top of letrec and lambda. Note that the definition below is as hygienic as possible considering the specification (in particular, invisible uses of alambda will not shadow self).
;; Define a version of lambda that binds the
;; anaphoric variable “self” to the function
;; being defined.
;;
;; Note the use of datum->syntax to specify the
;; scope of the anaphoric identifier.
(define-syntax alambda
(lambda (stx)
(syntax-case stx ()
[(alambda lambda-list . body)
(with-syntax ([name (datum->syntax #'alambda 'self)])
#'(letrec ([name (lambda lambda-list . body)])
name))])))
;; We can define let in terms of alambda as usual.
(define-syntax let/alambda
(syntax-rules ()
[(_ ((var val) ...) . body)
((alambda (var ...) . body) val ...)]))
;; The let/alambda macro does not shadow the outer
;; alambda's anaphoric variable, which is lexical
;; with regard to the alambda form.
((alambda (n)
(if (zero? n)
1
(let/alambda ([n-1 (- n 1)])
(* (self n-1) n))))
10)
;=> 3628800
Most people avoid anaphoric operators since they make the structure of the code less recognizable. In addition, refactoring can introduce problems rather easily. (Consider what happens when you wrap the let/alambda form in the factorial function above in another alambda form. It's easy to overlook uses of self, especially if you're not reminded of it being relevant by having to type it explicitly.) It is therefore generally preferable to use explicit names. A “labeled” version of lambda that allows this can be defined using a simple syntax-rules macro:
;; Define a version of lambda that allows the
;; user to specifiy a name for the function
;; being defined.
(define-syntax llambda
(syntax-rules ()
[(_ name lambda-list . body)
(letrec ([name (lambda lambda-list . body)])
name)]))
;; The factorial function can be expressed
;; using llambda.
((llambda fac (n)
(if (zero? n)
1
(* (fac (- n 1)) n)))
10)
;=> 3628800
I have found a way using continuations to have anonymous lambdas call themselves and then using Racket macros to disguise the syntax so the anonymous lambda appears to have a "self" operator. I don't know if this solution is possible in other versions of Scheme since it depends on the Call-with-composable-continuation function of racket and the Macro to hide the syntax uses syntax parameters.
The basic idea is this, illustrated with the factorial function.
( (lambda (n)
(call-with-values
(lambda () (call-with-composable-continuation
(lambda (k) (values k n))))
(lambda (k n)
(cond
[(= 0 n) 1]
[else (* n (k k (- n 1)))])))) 5)
The continuation k is the call to the anonymous factorial function, which takes two arguments, the first being the continuation itself. So that when in the body we execute (k k N) that is equivalent to the anonymous function calling itself (in the same way that a recursive named lambda would do).
We then disguise the underlying form with a macro. Rackets syntax-parameters allow the transformation of (self ARGS ...) to (k k ARGS ... )
so we can have:
((lambda-with-self (n)
(cond
[(= 0 n) 0]
[(= 1 n) 1]
[else (* n (self (- n 1)))])) 5)
The complete Racket program to do this is:
#lang racket
(require racket/stxparam) ;required for syntax-parameters
( define-syntax-parameter self (λ (stx) (raise-syntax-error #f "not in `lambda-with-self'" stx)))
(define-syntax-rule
(lambda-with-self (ARG ... ) BODY ...)
(lambda (ARG ...)
(call-with-values
(lambda ()(call/comp (lambda (k) (values k ARG ...))))
(lambda (k ARG ...)
(syntax-parameterize ([self (syntax-rules ( )[(self ARG ...) (k k ARG ...)])])
BODY ...)))))
;Example using factorial function
((lambda-with-self (n)
(cond
[(= 0 n) 0]
[(= 1 n) 1]
[else (* n (self (- n 1)))])) 5)
This also answers my previous question about the differences between the different kinds of continuations.
Different kinds of continuations in Racket
This only works because unlike call-with-current-continuation, call-with-composable-continuation doesn't abort back to a continuation prompt but invokes the continuation at the place it was invoked.

Resources