PSL Manual 7 February 1983 Function Definition
section 10.0 page 10.1
CHAPTER 10
CHAPTER 10
CHAPTER 10
FUNCTION DEFINITION AND BINDING
FUNCTION DEFINITION AND BINDING
FUNCTION DEFINITION AND BINDING
10.1. Function Definition in PSL . . . . . . . . . . 10.1
10.1.1. Notes on Code Pointers . . . . . . . . . 10.1
10.1.2. Functions Useful in Function Definition. . . . 10.2
10.1.3. Function Definition in LISP Syntax . . . . . 10.4
10.1.4. Function Definition in RLISP Syntax . . . . . 10.6
10.1.5. Low Level Function Definition Primitives . . . 10.6
10.1.6. Function Type Predicates. . . . . . . . . 10.7
10.2. Variables and Bindings. . . . . . . . . . . . 10.8
10.2.1. Binding Type Declaration. . . . . . . . . 10.8
10.2.2. Binding Type Predicates . . . . . . . . . 10.9
10.3. User Binding Functions. . . . . . . . . . . . 10.10
10.3.1. Funargs, Closures and Environments . . . . . 10.10
10.1. Function Definition in PSL
10.1. Function Definition in PSL
10.1. Function Definition in PSL
Functions in PSL are GLOBAL entities. To avoid function-variable naming
clashes, the Standard LISP Report required that no variable have the same
name as a function. There is no conflict in PSL, as separate function
cells and value cells are used. A warning message is given for
compatibility. The first major section in this chapter describes how to
define new functions; the second describes the binding of variables in PSL.
The final section presents binding functions useful in building new
interpreter functions.
10.1.1. Notes on Code Pointers
10.1.1. Notes on Code Pointers
10.1.1. Notes on Code Pointers
Print
____ _______ Print
A code-pointer may be displayed by the Print functions or expanded by
Explode
Explode
Explode. The value appears in the convention of the implementation
(#<Code:a nnnn>, where a is the number of arguments of the function, and
____ _______
nnnn is the function's entry point, on the DEC-20 and VAX). A code-pointer
Compress
Compress
may not be created by Compress. (See Chapter 12 for descriptions of
Explode Compress
Explode Compress ____ _______
Explode and Compress.) The code-pointer associated with a compiled
GetD
GetD
function may be retrieved by GetD and is valid as long as PSL is in
execution (on the DEC-20 and VAX, compiled code is not relocated, so
PutD
____ _______ ____ _______ PutD
code-pointers do not change). A code-pointer may be stored using PutD,
Put SetQ
Put SetQ
Put, SetQ and the like or by being bound to a variable. It may be checked
Eq
Eq ____ _______
for equivalence by Eq. The value may be checked for being a code-pointer
CodeP
CodeP
by the CodeP function.
Function Definition 7 February 1983 PSL Manual
page 10.2 section 10.1
10.1.2. Functions Useful in Function Definition
10.1.2. Functions Useful in Function Definition
10.1.2. Functions Useful in Function Definition
__
In PSL, ids have a function cell that usually contains an executable
instruction which either JUMPs directly to the entry point of a compiled
function or executes a CALL to an auxiliary routine that handles
interpreted functions, undefined functions, or other special services (such
________
as auto-loading functions, etc). The user can pass anonymous function
____ _______
objects around either as a code-pointer, which is a tagged object referring
______
to a compiled code block, or a lambda expression, representing an
interpreted function.
PutD
PutD _____ __ ____ _____ ____ ______ ____ _______ __ ____
(PutD FNAME:id TYPE:ftype BODY:{lambda,code-pointer}): id expr
_____ ____ ____
Creates a function with name FNAME and type TYPE, with BODY as
PutD
PutD
the function definition. If successful, PutD returns the name of
the defined function.
____ _______
If the body is a code-pointer or is compiled (i.e. !*COMP=T as
the function was defined), a special instruction to jump to the
start of the code is placed in the function cell. If it is a
______
lambda, the lambda expression is saved on the property list under
the indicator !*LAMBDALINK and a call to an interpreter function
LambdaLink
LambdaLink
(LambdaLink) is placed in the function cell.
____ ____ _____
The TYPE is recorded on the property list of FNAME if it is not
____
____
____
expr
expr
an expr.
[??? We need to add code to check that the the arglist has no
[??? We need to add code to check that the the arglist has no
[??? We need to add code to check that the the arglist has no
more than 15 arguments for exprs, 1 argument for fexprs and
more than 15 arguments for exprs, 1 argument for fexprs and
more than 15 arguments for exprs, 1 argument for fexprs and
macros, and ??? for nexprs. Declaration mechanisms to avoid
macros, and ??? for nexprs. Declaration mechanisms to avoid
macros, and ??? for nexprs. Declaration mechanisms to avoid
overhead also need to be available. (In fact are available
overhead also need to be available. (In fact are available
overhead also need to be available. (In fact are available
for the compiler, although still poorly documented.) When
for the compiler, although still poorly documented.) When
for the compiler, although still poorly documented.) When
should we expand macros? ???]
should we expand macros? ???]
should we expand macros? ???]
PutD GetD
PutD _____ GetD ____ _____
After using PutD on FNAME, GetD returns a pair of the the FNAME's
____ ____
(TYPE . BODY).
GlobalP
GlobalP
The GlobalP predicate returns T if queried with the defined
_____
function's name. If the function FNAME has already been declared
as a GLOBAL or FLUID variable the warning:
*** FNAME is a non-local variable
_____
occurs, but the function is defined. If function FNAME is
already defined, a warning message appears:
*** Function FNAME has been redefined
____
Note: All function types may be compiled.
The following switches are useful when defining functions.
PSL Manual 7 February 1983 Function Definition
section 10.1 page 10.3
__________ ______
!*REDEFMSG [Initially: T] switch
If !*REDEFMSG is not NIL, the message
*** Function `FOO' has been redefined
is printed whenever a function is redefined.
__________ ______
!*USERMODE [Initially: T] switch
Controls action on redefinition of a function. All functions
defined if !*USERMODE is T are flagged USER. Functions which are
flagged USER can be redefined freely. If an attempt is made to
redefine a function which is not flagged USER, the query
Do you really want to redefine the system function `FOO'?
is made, requiring a Y, N, YES, NO, or B response. B starts the
break loop, so that one can change the setting of !*USERMODE.
After exiting the break loop, one must answer Y, Yes, N, or No.
YesP
YesP
See YesP in Chapter 13. If !*UserMode is NIL, all functions can
be redefined freely, and all functions defined have the USER flag
removed. This provides some protection from redefining system
functions.
__________ ______
!*COMP [Initially: NIL] switch
PutD
PutD
The value of !*COMP controls whether or not PutD compiles the
function defined in its arguments before defining it. If !*COMP
is NIL the function is defined as a lambda expression. If !*COMP
is non-NIL, the function is first compiled. Compilation produces
certain changes in the semantics of functions, particularly FLUID
type access.
GetD
GetD _ ___ ___ ____ ____
(GetD U:any): {NIL, pair} expr
_
If U is not the name of a defined function, NIL is returned. If
_ ____
U is a defined function then the pair
____ _____ _____ _____
____ _____ _____ _____
____ _____ _____ _____
expr, fexpr, macro, nexpr
expr, fexpr, macro, nexpr ____ _______ ______
({expr, fexpr, macro, nexpr} . {code-pointer, lambda}) is
returned.
CopyD
CopyD ___ __ ___ __ ___ __ ____
(CopyD NEW:id OLD:id): NEW:id expr
___ ___
The function body and type for NEW become the same as OLD. If no
___
definition exists for OLD an error:
***** OLD has no definition in COPYD
Function Definition 7 February 1983 PSL Manual
page 10.4 section 10.1
___
is given. NEW is returned.
RemD
RemD _ __ ___ ____ ____
(RemD U:id): {NIL, pair} expr
_
Removes the function named U from the set of defined functions.
GetD
____ GetD
Returns the (ftype . function) pair or NIL, as does GetD. The
________ _
function type attribute of U is removed from the property list of
_
U.
10.1.3. Function Definition in LISP Syntax
10.1.3. Function Definition in LISP Syntax
10.1.3. Function Definition in LISP Syntax
De Df Dn Dm Ds
De Df Dn Dm Ds
The functions De, Df, Dn, Dm, and Ds are most commonly used in the LISP
syntax form of PSL. They are difficult to use from RLISP as there is not a
convenient way to represent the argument list. The functions are compiled
if the compiler is loaded and the GLOBAL !*COMP is T.
De
De _____ __ ______ __ ____ __ ____ __ _____
(De FNAME:id PARAMS:id-list [FN:form]): id macro
____
____
____
expr
_____ expr ____ __
Defines the function named FNAME, of type expr. The forms FN are
made into a lambda expression with the formal parameter list
1
______
PARAMS, and this is used as the body of the function.
Previous definitions of the function are lost. The name of the
_____
defined function, FNAME, is returned.
Df
Df _____ __ _____ __ ____ __ ___ __ _____
(Df FNAME:id PARAM:id-list FN:any): id macro
_____
_____
_____
fexpr
_____ fexpr ____ __
Defines the function named FNAME, of type fexpr. The forms FN
are made into a lambda expression with the formal parameter list
______
PARAMS, and this is used as the body of the function.
Previous definitions of the function are lost. The name of the
_____
defined function, FNAME, is returned.
Dn
Dn _____ __ _____ __ ____ __ ___ __ _____
(Dn FNAME:id PARAM:id-list FN:any): id macro
_____
_____
_____
nexpr
_____ nexpr ____ __
Defines the function named FNAME, of type nexpr. The forms FN
are made into a lambda expression with the formal parameter list
______
PARAMS, and this is used as the body of the function.
_______________
1
Or the compiled code pointer for the lambda expression if the compiler
is on.
PSL Manual 7 February 1983 Function Definition
section 10.1 page 10.5
Previous definitions of the function are lost. The name of the
_____
defined function, FNAME, is returned.
Dm
Dm _____ __ _____ __ ____ __ ___ __ _____
(Dm MNAME:id PARAM:id-list FN:any): id macro
_____
_____
_____
macro
_____ macro ____ __
Defines the function named FNAME, of type macro. The forms FN
are made into a lambda expression with the formal parameter list
______
PARAMS, and this is used as the body of the function.
Previous definitions of the function are lost. The name of the
_____
defined function, FNAME, is returned.
Ds
Ds _____ __ _____ __ ____ __ ___ __ _____
(Ds SNAME:id PARAM:id-list FN:any): id macro
______ _______
______ _______
______ _______
smacro Smacros
smacro _____ Smacros
Defines the smacro SNAME. Smacros are actually a syntactic
_____
_____
_____
macro
macro
notation for a special class of macros, those that essentially
treat the macro's argument as a list of arguments to be
substituted into the body of the expression and then expanded in
_____
_____
_____
macro
macro
line, rather than using the computational power of the macro to
defmacro
defmacro
customize code. Thus they are a special case of defmacro. See
also the BackQuote facility.
For example:
Lisp syntax:
To make a substitution macro for
FIRST ->CAR we could say
(DM FIRST(X)
(LIST 'CAR (CADR X)))
Instead the following is clearer
(DS FIRST(X)
(CAR X))
10.1.4. Function Definition in RLISP Syntax
10.1.4. Function Definition in RLISP Syntax
10.1.4. Function Definition in RLISP Syntax
[??? THIS IS NOT SUFFICIENT DOCUMENTATION! Either move it all to
[??? THIS IS NOT SUFFICIENT DOCUMENTATION! Either move it all to
[??? THIS IS NOT SUFFICIENT DOCUMENTATION! Either move it all to
chapter 3 or do a better job here. ???]
chapter 3 or do a better job here. ???]
chapter 3 or do a better job here. ???]
In RLISP syntax, procedures are defined by using the Procedure construct,
as discussed in Chapter 3.
mode type PROCEDURE name(args);
body;
where mode is SYSLISP or LISP or SYMBOLIC and defaults to LISP, and type
defaults to EXPR.
Function Definition 7 February 1983 PSL Manual
page 10.6 section 10.1
10.1.5. Low Level Function Definition Primitives
10.1.5. Low Level Function Definition Primitives
10.1.5. Low Level Function Definition Primitives
PutD GetD
PutD GetD
The following functions are used especially by PutD and GetD, defined
Eval Apply
Eval Apply
above in Section 10.1.2, and by Eval and Apply, defined in Chapter 11.
FUnBoundP
FUnBoundP _ __ _______ ____
(FUnBoundP U:id): boolean expr
________ _
Tests whether there is a definition in the function cell of U;
returns NIL if so, T if not.
Note: Undefined functions actually call a special function,
UndefinedFunction Error FUnBoundP
UndefinedFunction Error FUnBoundP
UndefinedFunction, that invokes Error. FUnBoundP defines
UndefinedFunction
UndefinedFunction
"unbound" to mean "calls UndefinedFunction".
FLambdaLinkP
FLambdaLinkP _ __ _______ ____
(FLambdaLinkP U:id): boolean expr
_
Tests whether U is an interpreted function; return T if so, NIL
if not. This is done by checking for the special code-address of
lambdaLink
lambdaLink
the lambdaLink function, which calls the interpreter.
FCodeP
FCodeP _ __ _______ ____
(FCodeP U:id): boolean expr
_
Tests whether U is a compiled function; returns T if so, NIL if
not.
MakeFUnBound
MakeFUnBound _ __ ___ ____
(MakeFUnBound U:id): NIL expr
_
Makes U an undefined function by planting a special call to an
UndefinedFunction
UndefinedFunction ________ _
error function, UndefinedFunction, in the function cell of U.
MakeFLambdaLink
MakeFLambdaLink _ __ ___ ____
(MakeFLambdaLink U:id): NIL expr
_
Makes U an interpreted function by planting a special call to an
lambdaLink
lambdaLink
interpreter support function (lambdaLink) function in the
________ _
function cell of U.}
MakeFCode
MakeFCode _ __ _ ____ _______ ___ ____
(MakeFCode U:id C:code-pointer): NIL expr
_
Makes U a compiled function by planting a special JUMP to the
_
code-address associated with C.
GetFCodePointer
GetFCodePointer _ __ ____ _______ ____
(GetFCodePointer U:id): code-pointer expr
____ _______ _
Gets the code-pointer for U.
PSL Manual 7 February 1983 Function Definition
section 10.1 page 10.7
Code!-Number!-Of!-Arguments
Code!-Number!-Of!-Arguments _ ____ _______ ___ _______ ____
(Code!-Number!-Of!-Arguments C:code-pointer): {NIL,integer} expr
Some compiled functions have the argument number they expect
_
stored in association with the codepointer C. This integer, or
NIL is returned.
_____ ____
_____ ____
_____ ____
[??? Should be extended for nexprs and declared exprs. ???]
[??? Should be extended for nexprs and declared exprs. ???]
[??? Should be extended for nexprs and declared exprs. ???]
10.1.6. Function Type Predicates
10.1.6. Function Type Predicates
10.1.6. Function Type Predicates
See Section 2.7 for a discussion of the function types available in PSL.
ExprP
ExprP _ ___ _______ ____
(ExprP U:any): boolean expr
____
____
____
expr
_ ____ _______ ______ __ expr
Test if U is a code-pointer, lambda form, or an id with expr
definition.
FExprP
FExprP _ ___ _______ ____
(FExprP U:any): boolean expr
_____
_____
_____
fexpr
_ __ fexpr
Test if U is an id with fexpr definition.
NExprP
NExprP _ ___ _______ ____
(NExprP U:any): boolean expr
_____
_____
_____
nexpr
_ __ nexpr
Test if U is an id with nexpr definition.
MacroP
MacroP _ ___ _______ ____
(MacroP U:any): boolean expr
_____
_____
_____
macro
_ __ macro
Test if U is an id with macro definition.
10.2. Variables and Bindings
10.2. Variables and Bindings
10.2. Variables and Bindings
__
Variables in PSL are ids, and associated values are usually stored in and
__
retrieved from the value cell of this id. If variables appear as
Prog
Prog
parameters in lambda expressions or in Prog's, the contents of the value
cell are saved on a binding stack. A new value or NIL is stored in the
Prog
Prog
value cell and the computation proceeds. On exit from the lambda or Prog
the old value is restored. This is called the "shallow binding" model of
LISP. It is chosen to permit compiled code to do binding efficiently. For
even more efficiency, compiled code may eliminate the variable names and
simply keep values in registers or a stack. The scope of a variable is the
range over which the variable has a defined value. There are three
different binding mechanisms in PSL.
LOCAL BINDING Only compiled functions bind variables locally. Local
Function Definition 7 February 1983 PSL Manual
page 10.8 section 10.2
variables occur as formal parameters in lambda expressions
Prog
Prog
and as LOCAL variables in Prog's. The binding occurs as a
Prog
Prog
lambda expression is evaluated or as a Prog form is
executed. The scope of a local variable is the body of the
function in which it is defined.
FLUID BINDING FLUID variables are GLOBAL in scope but may occur as formal
Prog
Prog
parameters or Prog form variables. In interpreted
functions, all formal parameters and LOCAL variables are
considered to have FLUID binding until changed to LOCAL
binding by compilation. A variable can be treated as a
FLUID only by declaration. If FLUID variables are used as
parameters or LOCALs they are rebound in such a way that the
previous binding may be restored. All references to FLUID
variables are to the currently active binding. Access to
the values is by name, going to the value cell.
GLOBAL BINDING GLOBAL variables may never be rebound. Access is to the
value bound to the variable. The scope of a GLOBAL variable
is universal. Variables declared GLOBAL may not appear as
Prog
Prog
parameters in lambda expressions or as Prog form variables.
A variable must be declared GLOBAL prior to its use as a
GLOBAL variable since the default type for undeclared
variables is FLUID. Note that the interpreter does not stop
one from rebinding a global variable. The compiler will
issue a warning in this situation.
10.2.1. Binding Type Declaration
10.2.1. Binding Type Declaration
10.2.1. Binding Type Declaration
Fluid
Fluid ______ __ ____ ___ ____
(Fluid IDLIST:id-list): NIL expr
__ ______ __
The ids in IDLIST are declared as FLUID type variables (ids not
______
previously declared are initialized to NIL). Variables in IDLIST
already declared FLUID are ignored. Changing a variable's type
from GLOBAL to FLUID is not permissible and results in the error:
***** ID cannot be changed to FLUID
Global
Global ______ __ ____ ___ ____
(Global IDLIST:id-list): NIL expr
__ ______ __
The ids of IDLIST are declared GLOBAL type variables. If an id
has not been previously declared, it is initialized to NIL.
Variables already declared GLOBAL are ignored. Changing a
variable's type from FLUID to GLOBAL is not permissible and
results in the error:
***** ID cannot be changed to GLOBAL
PSL Manual 7 February 1983 Function Definition
section 10.2 page 10.9
UnFluid
UnFluid ______ __ ____ ___ ____
(UnFluid IDLIST:id-list): NIL expr
______
The variables in IDLIST which have been declared as FLUID
variables are no longer considered as FLUID variables. Others
are ignored. This affects only compiled functions, as free
variables in interpreted functions are automatically considered
FLUID (see [Griss 81]).
10.2.2. Binding Type Predicates
10.2.2. Binding Type Predicates
10.2.2. Binding Type Predicates
FluidP
FluidP _ ___ _______ ____
(FluidP U:any): boolean expr
_
If U is FLUID (by declaration only), T is returned; otherwise,
NIL is returned.
GlobalP
GlobalP _ ___ _______ ____
(GlobalP U:any): boolean expr
_
If U has been declared GLOBAL or is the name of a defined
function, T is returned; else NIL is returned.
UnBoundP
UnBoundP _ __ _______ ____
(UnBoundP U:id): boolean expr
_
Tests whether U has no value.
10.3. User Binding Functions
10.3. User Binding Functions
10.3. User Binding Functions
The following functions are available to build one's own interpreter
functions that use the built-in FLUID binding mechanism, and interact well
with the automatic unbinding that takes place during Throw and Error calls.
[??? Are these correct when Environments are managed correctly ???]
[??? Are these correct when Environments are managed correctly ???]
[??? Are these correct when Environments are managed correctly ???]
UnBindN
UnBindN _ _______ _________ ____
(UnBindN N:integer): Undefined expr
Prog
Prog
Used in user-defined interpreter functions (like Prog) to restore
_
previous bindings to the last N values bound.
LBind1
LBind1 ______ __ ___________ ___ _________ ____
(LBind1 IDNAME:id VALUETOBIND:any): Undefined expr
______
Support for LAMBDA-like binding. The current value of IDNAME is
___________
saved on the binding stack; the value of VALUETOBIND is then
______
bound to IDNAME.
Function Definition 7 February 1983 PSL Manual
page 10.10 section 10.3
PBind1
PBind1 ______ __ _________ ____
(PBind1 IDNAME:id): Undefined expr
Prog
Prog ______
Support for Prog. Binds NIL to IDNAME after saving value on the
LBind1
LBind1 ______
binding stack. Essentially LBind1(IDNAME, NIL)
10.3.1. Funargs, Closures and Environments
10.3.1. Funargs, Closures and Environments
10.3.1. Funargs, Closures and Environments
[??? Not yet connected to V3 ???]
[??? Not yet connected to V3 ???]
[??? Not yet connected to V3 ???]
We have an experimental implementation of Baker's re-rooting funarg
scheme [Baker 78], in which we always re-root upon binding; this permits
efficient use of a GLOBAL value cell in the compiler. We are also
considering implementing a restricted FUNARG or CLOSURE mechanism. The
implementation we have does not work with the current version of PSL.
This currently uses a module (ALTBIND) to redefine the fluid binding
_ ____
mechanism of PSL to be functionally equivalent to an a-list binding scheme.
However, it retains the principal advantage of the usual shallow binding
scheme: variable lookup is extremely cheap -- just look in a value cell.
Typical LISP programs currently run about 8% slower if using ALTBIND than
with the initial shallow binding mechanism. It is expected that this 8%
difference will go away presently. This mechanism will also probably
become a standard part of PSL, rather than an add on module.
To use ALTBIND simply do "load altbind;" ["(load altbind)" in LISP].
Existing code, both interpreted and compiled, should then commence using
the new binding mechanism.
The following functions are of most interest to the user:
Closure
Closure _ ____ ____ _____
(Closure U:form): form macro
Function
Function
This is similar to Function, but returns a function closure
Function
Function
including environment information, similar to Function in LISP
Function* Eval Apply
Function* Eval Apply
1.5 and Function* in LISP 1.6 and MACLISP. Eval and Apply are
redefined to handle closures correctly. Currently only closures
____
____
____
expr
expr
of exprs are supported.
EvalInEnvironment
EvalInEnvironment _ ____ ___ ___ _______ ___ ____
(EvalInEnvironment F:form ENV:env-pointer): any expr
ApplyInEnvironment
ApplyInEnvironment __ ________ ____ ____ ____ ___ ___ _______ ___ ____
(ApplyInEnvironment FN:function ARGS:form-list ENV:env-pointer): any expr
Eval Apply
Eval Apply
These are like Eval and Apply, but take an extra, last argument,
and environment pointer. They perform their work in this
environment instead of the current one.
The following functions should be used with care:
PSL Manual 7 February 1983 Function Definition
section 10.3 page 10.11
CaptureEnvironment
CaptureEnvironment ___ _______ ____
(CaptureEnvironment ): env-pointer expr
Save the current bindings to be restored at some later point.
CaptureEnvironment
CaptureEnvironment
This is best used inside a closure. CaptureEnvironment returns
____
an environment pointer. This object is normally a circular list
structure, and so should not be printed. The same warning
applies to closures, which contain environment pointers. It is
hoped that environment pointers will be made a new LISP data type
soon, and will be made to print safely, relaxing this
restriction.
[??? add true envpointer ???]
[??? add true envpointer ???]
[??? add true envpointer ???]
RestoreEnvironment
RestoreEnvironment ___ ___ _______ _________ ____
(RestoreEnvironment PTR:env-pointer): Undefined expr
Restore old bindings to what they were in the captured
___
environment, PTR.
ClearBindings
ClearBindings _________ ____
(ClearBindings ): Undefined expr
Restore bindings to top level, i.e strip the entire stack.
For a demonstration of closures, do (in RLISP)
`in "PU:altbind-tests.red";'.
[??? Give a practical example ???]
[??? Give a practical example ???]
[??? Give a practical example ???]