(define-record Var (name)) (define-record Const (value)) (define-record Lam (formals body)) (define-record Ap (fun args))Let us define a procedure
check
that determines if the parameters
of every lambda expression in a program are distinct.
(define check (lambda (e) (cond ((Const? e) #t) ((Var? e) #t) ((Lam? e) (and (check-unique (Lam->formals e)) (check (Lam->body e)))) ((Ap? e) (and (check (Ap->fun e)) (andmap check (Ap->args e))))))) (define andmap (lambda (f l) (if (null? l) #t (and (f (car l)) (andmap f (cdr l)))))) (define check-unique (lambda (names) (if (null? names) #t (and (not (member (car names) (cdr names))) (check-unique (cdr names))))))We can use the syntactic form
variant case
to furhter simplify
check
.
(define check (lambda (e) (variant-case e (Const (value) #t) (Var (name) #t) (Lam (formals body) (and (check-unique formals) (check body))) (Ap (fun args) (and (check fun) (andmap check args))))))
(+ 1 2)
is not necessarily equal to
3. The reason is that +
may be locally bound. For example,
consider
((lambda (+) (+ 1 2)) -)This expression appears to yield -1, but again
-
might be
locally bound. Now what about:
(lambda (+) +)This is an identity function, no matter where it appears in a program.
Certain constructs of any programming language are binders. The Scheme contructs that are binders are:
(lambda (x) e) ^ (let ((x e)) e) ^A bound occurence is any use of a bound variable. Consider the following.
(lambda (a) (a (lambda (a) a) a)) 1 2 3 4 5Occurrences 1 and 3 are binding occurrences, while 2, 4, 5 are bound occurrences. Uses 2 and 5 refer to binding 1, while use 4 refers to binding 3.
The scope of a binding is the region of text within its binder minus any regions which bind the same name. The bound variables of an expression are those variables that occur bound in an expression. The free variables of an expression are those variables that occur but are not bound. The previous example has no free variables. Since English is rather imprecise, let's make these definitions in math.
x occurs free in e if and only if
e = x OR x = (lambda (y[1] ... y[n]) e') and x occurs free in e' and x not in any y[i] OR x = (e[0] e[1] ... e[n]) and x occurs free in at least one of e[i]Based on this definition we can write occurs-free.
(define occurs-free? (lambda (e x) (variant-case e (Var (name) (equal? name x)) (Lam (formals body) (and (occurs-free? body x) (not (member x formals)))) (Ap (fun args) (or (occurs-free? fun x) (ormap (occurs-free? (lambda (a) (occurs-free? a x)) args)))))))
x occurs bound in e if and only if
e = (lambda (y[1] ... y[n]) e') and x = y[i] for some i or x occurs bound in e' OR (e[0] e[1] ... e[n]) and x occurs bound in at least one e[i]