This is a short description of some reflective features fully detailed in chapter 8 of my book . A further version is analyzed in ICFP96.
This file gives some indications on the reflective capabilities as well as the first-class environments. It is not a complete specification but only a short sketch of what they are. You will have to read the book to know more about these features and chiefly how to implement them in a byte-code compiler.
The export special form returns a first-class environment capturing bindings. Two forms exist:
(export variable-names ... )captures all the mentioned variables whether global or local.
(export)captures all variables whether global or local. This is something that might be also called
First-class environments are useful with a binary eval function named
eval/b in the book.
(eval/b expression environment)returns the value of the expression considered as a program to be evaluated in the specified environment. Free variables of the expression take their value from the environment. An error is signalled if a variable is missing from that environment ie the environment cannot be automatically enriched with new bindings.
A first-class environment may be enriched to contain a new
variable. This is the role of the
function that returns a new
environment containing locations associated to the given names.
(enrich environment (quote variable-name) ... )The first argument is not modified but a new first-class environment is built instead. The fresh bindings may shadow old bindings with the same name.
A proposal to make closures less opaque is provided with the following special form:
(reflective-lambda (variables) (exportations) . body)The variables mentioned in the exportations are the only bindings that may be used out of the closure if retrieving them, packed in a first-class environment, with the following function:
eval/b, first-class environments may
be used more statically
within import forms. The
import special form is the following:
(import (variables) environment . body)First, the environment is evaluated then the body is evaluated in an extended environment where the free variables of body that are mentioned in (variables) are assimilated to the locations with the same name in the environment. This means that body only pays for the variables that appear in (variables), a static list of variable names. It is suggested in the book that if you do not mention variables then all free variables of body are looked up in the provided environment. This is somewhat similar to the quasi-static scope of Lee and Friedman POPL92.
I use it from place to place to control exceptions. The monitor special form takes care of them:
(monitor handler . body)First handler is evaluated and must yield a binary function then the body is evaluated and its final value is returned. If an exception occurs (and exceptions may be raised explicitly with the
(diagnose boolean value)signals value as an exception whose continuability is specified by boolean) then the dynamically most recently enclosing handler is appplied on a boolean and an exceptional value. This application is controlled by the next most recently dynamically enclosing handler. The botttom handler is left unspecified. If the handler returns a value, this value becomes the value of the
diagnosecall only if the boolean was true (meaning that it was a continuable exception) otherwise a "non continuable" exception is raised.
Another part of chapter 8 presents a reflective interpreter whose main features are:
eval/b, monitor features are present,
The last feature is:
(flambda (r . variables) body)returns a reflective object which when applied receives the current lexical environment in its first variable and the unevaluated arguments in its remaining variables (this is nearly equivalent to the old fexprs).
Of course, the interpreter can interpret itself.