BSD 4_3 development
[unix-history] / usr / lib / lisp / manual / ch8.r
CHAPTER 8
Functions, Fclosures, and Macros
8.1. valid function objects
There are many different objects which can occupy
the function field of a symbol object. Table 8.1, on
the following page, shows all of the possibilities,
how to recognize them, and where to look for documen-
tation.
8.2. functions
The basic Lisp function is the lambda function.
When a lambda function is called, the actual arguments
are evaluated from left to right and are lambda-bound
to the formal parameters of the lambda function.
An nlambda function is usually used for functions
which are invoked by the user at top level. Some
built-in functions which evaluate their arguments in
special ways are also nlambdas (e.g _\bc_\bo_\bn_\bd, _\bd_\bo, _\bo_\br).
When an nlambda function is called, the list of
unevaluated arguments is lambda bound to the single
formal parameter of the nlambda function.
Some programmers will use an nlambda function
when they are not sure how many arguments will be
passed. Then, the first thing the nlambda function
does is map _\be_\bv_\ba_\bl over the list of unevaluated argu-
ments it has been passed. This is usually the wrong
thing to do, as it will not work compiled if any of
the arguments are local variables. The solution is to
use a lexpr. When a lexpr function is called, the
arguments are evaluated and a fixnum whose value is
the number of arguments is lambda-bound to the single
formal parameter of the lexpr function. The lexpr can
then access the arguments using the _\ba_\br_\bg function.
When a function is compiled, _\bs_\bp_\be_\bc_\bi_\ba_\bl declarations
may be needed to preserve its behavior. An argument
is not lambda-bound to the name of the corresponding
formal parameter unless that formal parameter has been
declared _\bs_\bp_\be_\bc_\bi_\ba_\bl (see 12.3.2.2).
Functions, Fclosures, and Macros 8-1
Functions, Fclosures, and Macros 8-2
\e8_________________________________________________________________
informal name object type documentation
\e8_________________________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b_________________________________________________________________
interpreted list with _\bc_\ba_\br 8.2
lambda function _\be_\bq to lambda
\e8_________________________________________________________________
interpreted list with _\bc_\ba_\br 8.2
nlambda function _\be_\bq to nlambda
\e8_________________________________________________________________
interpreted list with _\bc_\ba_\br 8.2
lexpr function _\be_\bq to lexpr
\e8_________________________________________________________________
interpreted list with _\bc_\ba_\br 8.3
macro _\be_\bq to macro
\e8_________________________________________________________________
fclosure vector with _\bv_\bp_\br_\bo_\bp 8.4
_\be_\bq to fclosure
\e8_________________________________________________________________
compiled binary with discipline 8.2
lambda or lexpr _\be_\bq to lambda
function
\e8_________________________________________________________________
compiled binary with discipline 8.2
nlambda function _\be_\bq to nlambda
\e8_________________________________________________________________
compiled binary with discipline 8.3
macro _\be_\bq to macro
\e8_________________________________________________________________
foreign binary with discipline 8.5
subroutine of "subroutine"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
function of "function"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
integer function of "integer-function"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
real function of "real-function"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
C function of "c-function"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
double function of "double-c-function"[|\b-]
\e8_________________________________________________________________
foreign binary with discipline 8.5
structure function of "vector-c-function"[|\b-]
\e8_________________________________________________________________
array array object 9
\e8_________________________________________________________________
\e7\b|\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
\e9 |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
\e9 |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
\e9 |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
\e9 Table 8.1
____________________
\e9 [|\b-]Only the first character of the string is significant (i.e "s"
is ok for "subroutine")
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-3
Lambda and lexpr functions both compile into a
binary object with a discipline of lambda. However, a
compiled lexpr still acts like an interpreted lexpr.
8.3. macros
An important feature of Lisp is its ability to
manipulate programs as data. As a result of this,
most Lisp implementations have very powerful macro
facilities. The Lisp language's macro facility can be
used to incorporate popular features of the other
languages into Lisp. For example, there are macro
packages which allow one to create records (ala Pas-
cal) and refer to elements of those records by the
field names. The _\bs_\bt_\br_\bu_\bc_\bt package imported from Maclisp
does this. Another popular use for macros is to
create more readable control structures which expand
into _\bc_\bo_\bn_\bd, _\bo_\br and _\ba_\bn_\bd. One such example is the If
macro. It allows you to write
(_\bI_\bf (_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b0) _\bt_\bh_\be_\bn (_\bp_\br_\bi_\bn_\bt '_\bz_\be_\br_\bo) (_\bt_\be_\br_\bp_\br)
_\be_\bl_\bs_\be_\bi_\bf (_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b1) _\bt_\bh_\be_\bn (_\bp_\br_\bi_\bn_\bt '_\bo_\bn_\be) (_\bt_\be_\br_\bp_\br)
_\be_\bl_\bs_\be (_\bp_\br_\bi_\bn_\bt '|_\bI _\bg_\bi_\bv_\be _\bu_\bp|))
which expands to
(_\bc_\bo_\bn_\bd
((_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b0) (_\bp_\br_\bi_\bn_\bt '_\bz_\be_\br_\bo) (_\bt_\be_\br_\bp_\br))
((_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b1) (_\bp_\br_\bi_\bn_\bt '_\bo_\bn_\be) (_\bt_\be_\br_\bp_\br))
(_\bt (_\bp_\br_\bi_\bn_\bt '|_\bI _\bg_\bi_\bv_\be _\bu_\bp|)))
8.3.1. macro forms
A macro is a function which accepts a Lisp
expression as input and returns another Lisp
expression. The action the macro takes is called
macro expansion. Here is a simple example:
-> (_\bd_\be_\bf _\bf_\bi_\br_\bs_\bt (_\bm_\ba_\bc_\br_\bo (_\bx) (_\bc_\bo_\bn_\bs '_\bc_\ba_\br (_\bc_\bd_\br _\bx))))
first
-> (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc))
a
-> (_\ba_\bp_\bp_\bl_\by '_\bf_\bi_\br_\bs_\bt '(_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)))
(car '(a b c))
The first input line defines a macro called _\bf_\bi_\br_\bs_\bt.
Notice that the macro has one formal parameter, _\bx.
On the second input line, we ask the interpreter to
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-4
evaluate (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)). _\bE_\bv_\ba_\bl sees that _\bf_\bi_\br_\bs_\bt
has a function definition of type macro, so it
evaluates _\bf_\bi_\br_\bs_\bt's definition, passing to _\bf_\bi_\br_\bs_\bt, as
an argument, the form _\be_\bv_\ba_\bl itself was trying to
evaluate: (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)). The _\bf_\bi_\br_\bs_\bt macro chops
off the car of the argument with _\bc_\bd_\br, cons' a _\bc_\ba_\br
at the beginning of the list and returns
(_\bc_\ba_\br '(_\ba _\bb _\bc)), which _\be_\bv_\ba_\bl evaluates. The value _\ba
is returned as the value of (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)). Thus
whenever _\be_\bv_\ba_\bl tries to evaluate a list whose car
has a macro definition it ends up doing (at least)
two operations, the first of which is a call to the
macro to let it macro expand the form, and the
other is the evaluation of the result of the macro.
The result of the macro may be yet another call to
a macro, so _\be_\bv_\ba_\bl may have to do even more evalua-
tions until it can finally determine the value of
an expression. One way to see how a macro will
expand is to use _\ba_\bp_\bp_\bl_\by as shown on the third input
line above.
8.3.2. defmacro
The macro _\bd_\be_\bf_\bm_\ba_\bc_\br_\bo makes it easier to define
macros because it allows you to name the arguments
to the macro call. For example, suppose we find
ourselves often writing code like
(_\bs_\be_\bt_\bq _\bs_\bt_\ba_\bc_\bk (_\bc_\bo_\bn_\bs _\bn_\be_\bw_\be_\bl_\bt _\bs_\bt_\ba_\bc_\bk). We could define a
macro named _\bp_\bu_\bs_\bh to do this for us. One way to
define it is:
-> (_\bd_\be_\bf _\bp_\bu_\bs_\bh
(_\bm_\ba_\bc_\br_\bo (_\bx) (_\bl_\bi_\bs_\bt '_\bs_\be_\bt_\bq (_\bc_\ba_\bd_\bd_\br _\bx) (_\bl_\bi_\bs_\bt '_\bc_\bo_\bn_\bs (_\bc_\ba_\bd_\br _\bx) (_\bc_\ba_\bd_\bd_\br _\bx)))))
push
then (_\bp_\bu_\bs_\bh _\bn_\be_\bw_\be_\bl_\bt _\bs_\bt_\ba_\bc_\bk) will expand to the form
mentioned above. The same macro written using def-
macro would be:
-> (_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bp_\bu_\bs_\bh (_\bv_\ba_\bl_\bu_\be _\bs_\bt_\ba_\bc_\bk)
(_\bl_\bi_\bs_\bt '_\bs_\be_\bt_\bq ,_\bs_\bt_\ba_\bc_\bk (_\bl_\bi_\bs_\bt '_\bc_\bo_\bn_\bs ,_\bv_\ba_\bl_\bu_\be ,_\bs_\bt_\ba_\bc_\bk)))
push
Defmacro allows you to name the arguments of the
macro call, and makes the macro definition look
more like a function definition.
\e9
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-5
8.3.3. the backquote character macro
The default syntax for FRANZ LISP has four
characters with associated character macros. One
is semicolon for comments. Two others are the
backquote and comma which are used by the backquote
character macro. The fourth is the sharp sign
macro described in the next section.
The backquote macro is used to create lists
where many of the elements are fixed (quoted). This
makes it very useful for creating macro defini-
tions. In the simplest case, a backquote acts just
like a single quote:
->`(_\ba _\bb _\bc _\bd _\be)
(a b c d e)
If a comma precedes an element of a backquoted list
then that element is evaluated and its value is put
in the list.
->(_\bs_\be_\bt_\bq _\bd '(_\bx _\by _\bz))
(x y z)
->`(_\ba _\bb _\bc ,_\bd _\be)
(a b c (x y z) e)
If a comma followed by an at sign precedes an ele-
ment in a backquoted list, then that element is
evaluated and spliced into the list with _\ba_\bp_\bp_\be_\bn_\bd.
->`(_\ba _\bb _\bc ,@_\bd _\be)
(a b c x y z e)
Once a list begins with a backquote, the commas may
appear anywhere in the list as this example shows:
->`(_\ba _\bb (_\bc _\bd ,(_\bc_\bd_\br _\bd)) (_\be _\bf (_\bg _\bh ,@(_\bc_\bd_\bd_\br _\bd) ,@_\bd)))
(a b (c d (y z)) (e f (g h z x y z)))
It is also possible and sometimes even useful to
use the backquote macro within itself. As a final
demonstration of the backquote macro, we shall
define the first and push macros using all the
power at our disposal: defmacro and the backquote
macro.
->(_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bf_\bi_\br_\bs_\bt (_\bl_\bi_\bs_\bt) `(_\bc_\ba_\br ,_\bl_\bi_\bs_\bt))
first
->(_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bp_\bu_\bs_\bh (_\bv_\ba_\bl_\bu_\be _\bs_\bt_\ba_\bc_\bk) `(_\bs_\be_\bt_\bq ,_\bs_\bt_\ba_\bc_\bk (_\bc_\bo_\bn_\bs ,_\bv_\ba_\bl_\bu_\be ,_\bs_\bt_\ba_\bc_\bk)))
stack
\e9
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-6
8.3.4. sharp sign character macro
The sharp sign macro can perform a number of
different functions at read time. The character
directly following the sharp sign determines which
function will be done, and following Lisp s-
expressions may serve as arguments.
8.3.4.1. conditional inclusion
If you plan to run one source file in more than
one environment then you may want to some pieces
of code to be included or not included depend-
ing on the environment. The C language uses
"#ifdef" and "#ifndef" for this purpose, and
Lisp uses "#+" and "#-". The environment that
the sharp sign macro checks is the
(_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be_\bs) list which is initialized when
the Lisp system is built and which may be
altered by (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be _\bf_\bo_\bo) and
(_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bn_\bo_\bf_\be_\ba_\bt_\bu_\br_\be _\bb_\ba_\br) The form of conditional
inclusion is
_\b#_\b+_\bw_\bh_\be_\bn _\bw_\bh_\ba_\bt
where _\bw_\bh_\be_\bn is either a symbol or an expression
involving symbols and the functions _\ba_\bn_\bd, _\bo_\br, and
_\bn_\bo_\bt. The meaning is that _\bw_\bh_\ba_\bt will only be read
in if _\bw_\bh_\be_\bn is true. A symbol in _\bw_\bh_\be_\bn is true
only if it appears in the (_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be_\bs)
list.
____________________________________________________
; suppose we want to write a program which references a file
; and which can run at ucb, ucsd and cmu where the file naming conventions
; are different.
;
-> (_\bd_\be_\bf_\bu_\bn _\bh_\bo_\bw_\bo_\bl_\bd (_\bn_\ba_\bm_\be)
(_\bt_\be_\br_\bp_\br)
(_\bl_\bo_\ba_\bd #+(_\bo_\br _\bu_\bc_\bb _\bu_\bc_\bs_\bd) "/_\bu_\bs_\br/_\bl_\bi_\bb/_\bl_\bi_\bs_\bp/_\ba_\bg_\be_\bs._\bl"
#+_\bc_\bm_\bu "/_\bu_\bs_\br/_\bl_\bi_\bs_\bp/_\bd_\bo_\bc/_\ba_\bg_\be_\bs._\bl")
(_\bp_\ba_\bt_\bo_\bm _\bn_\ba_\bm_\be)
(_\bp_\ba_\bt_\bo_\bm " _\bi_\bs ")
(_\bp_\br_\bi_\bn_\bt (_\bc_\bd_\br (_\ba_\bs_\bs_\bo_\bc _\bn_\ba_\bm_\be _\ba_\bg_\be_\bf_\bi_\bl_\be)))
(_\bp_\ba_\bt_\bo_\bm "_\by_\be_\ba_\br_\bs _\bo_\bl_\bd")
(_\bt_\be_\br_\bp_\br))
____________________________________________________
The form
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-7
_\b#_\b-_\bw_\bh_\be_\bn _\bw_\bh_\ba_\bt
is equivalent to
_\b#_\b+_\b(_\bn_\bo_\bt _\bw_\bh_\be_\bn_\b) _\bw_\bh_\ba_\bt
8.3.4.2. fixnum character equivalents
When working with fixnum equivalents of charac-
ters, it is often hard to remember the number
corresponding to a character. The form
_\b#_\b/_\bc
is equivalent to the fixnum representation of
character c.
____________________________________________________
; a function which returns t if the user types y else it returns nil.
;
-> (_\bd_\be_\bf_\bu_\bn _\by_\be_\bs_\bo_\br_\bn_\bo _\bn_\bi_\bl
(_\bp_\br_\bo_\bg_\bn (_\ba_\bn_\bs)
(_\bs_\be_\bt_\bq _\ba_\bn_\bs (_\bt_\by_\bi))
(_\bc_\bo_\bn_\bd ((_\be_\bq_\bu_\ba_\bl _\ba_\bn_\bs #/_\by) _\bt)
(_\bt _\bn_\bi_\bl))))
____________________________________________________
8.3.4.3. read time evaluation
Occasionally you want to express a constant as a
Lisp expression, yet you don't want to pay the
penalty of evaluating this expression each time
it is referenced. The form
_\b#_\b._\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn
evaluates the expression at read time and
returns its value.
\e9
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-8
____________________________________________________
; a function to test if any of bits 1 3 or 12 are set in a fixnum.
;
-> (_\bd_\be_\bf_\bu_\bn _\bt_\be_\bs_\bt_\bi_\bt (_\bn_\bu_\bm)
(_\bc_\bo_\bn_\bd ((_\bz_\be_\br_\bo_\bp (_\bb_\bo_\bo_\bl_\be _\b1 _\bn_\bu_\bm #.(+ (_\bl_\bs_\bh _\b1 _\b1) (_\bl_\bs_\bh _\b1 _\b3) (_\bl_\bs_\bh _\b1 _\b1_\b2))))
_\bn_\bi_\bl)
(_\bt _\bt)))
____________________________________________________
8.4. fclosures
Fclosures are a type of functional object. The
purpose is to remember the values of some variables
between invocations of the functional object and to
protect this data from being inadvertently overwritten
by other Lisp functions. Fortran programs usually
exhibit this behavior for their variables. (In fact,
some versions of Fortran would require the variables
to be in COMMON). Thus it is easy to write a linear
congruent random number generator in Fortran, merely
by keeping the seed as a variable in the function. It
is much more risky to do so in Lisp, since any special
variable you picked, might be used by some other func-
tion. Fclosures are an attempt to provide most of the
same functionality as closures in Lisp Machine Lisp,
to users of FRANZ LISP. Fclosures are related to clo-
sures in this way:
(fclosure '(a b) 'foo) <==>
(let ((a a) (b b)) (closure '(a b) 'foo))
8.4.1. an example
____________________________________________________________
% lisp
Franz Lisp, Opus 38.60
->(defun code (me count)
(print (list 'in x))
(setq x (+ 1 x))
(cond ((greaterp count 1) (funcall me me (sub1 count))))
(print (list 'out x)))
code
->(defun tester (object count)
(funcall object object count) (terpri))
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-9
tester
->(setq x 0)
0
->(setq z (fclosure '(x) 'code))
fclosure[8]
-> (tester z 3)
(in 0)(in 1)(in 2)(out 3)(out 3)(out 3)
nil
->x
0
____________________________________________________________
The function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be creates a new object
that we will call an fclosure, (although it is
actually a vector). The fclosure contains a func-
tional object, and a set of symbols and values for
the symbols. In the above example, the fclosure
functional object is the function code. The set of
symbols and values just contains the symbol `x' and
zero, the value of `x' when the fclosure was
created.
When an fclosure is funcall'ed:
1) The Lisp system lambda binds the symbols in
the fclosure to their values in the fclosure.
2) It continues the funcall on the functional
object of the fclosure.
3) Finally, it un-lambda binds the symbols in the
fclosure and at the same time stores the
current values of the symbols in the fclosure.
Notice that the fclosure is saving the value
of the symbol `x'. Each time a fclosure is
created, new space is allocated for saving the
values of the symbols. Thus if we execute fclosure
again, over the same function, we can have two
independent counters:
____________________________________________________________
-> (setq zz (fclosure '(x) 'code))
fclosure[1]
-> (tester zz 2)
(in 0)(in 1)(out 2)(out 2)
-> (tester zz 2)
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-10
(in 2)(in 3)(out 4)(out 4)
-> (tester z 3)
(in 3)(in 4)(in 5)(out 6)(out 6)(out 6)
____________________________________________________________
8.4.2. useful functions
Here are some quick some summaries of func-
tions dealing with closures. They are more for-
mally defined in 2.8.4. To recap, fclosures are
made by (_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be '_\bl__\bv_\ba_\br_\bs '_\bg__\bf_\bu_\bn_\bc_\bo_\bb_\bj). l_vars is a
list of symbols (not containing nil), g_funcobj is
any object that can be funcalled. (Objects which
can be funcalled, include compiled Lisp functions,
lambda expressions, symbols, foreign functions,
etc.) In general, if you want a compiled function
to be closed over a variable, you must declare the
variable to be special within the function.
Another example would be:
(fclosure '(a b) #'(lambda (x) (plus x a)))
Here, the #' construction will make the compiler
compile the lambda expression.
There are times when you want to share vari-
ables between fclosures. This can be done if the
fclosures are created at the same time using
_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\bl_\bi_\bs_\bt. The function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\ba_\bl_\bi_\bs_\bt returns
an assoc list giving the symbols and values in the
fclosure. The predicate _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be_\bp returns t iff
its argument is a fclosure. Other functions
imported from Lisp Machine Lisp are _\bs_\by_\bm_\be_\bv_\ba_\bl-_\bi_\bn-
_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be, _\bl_\be_\bt-_\bf_\bc_\bl_\bo_\bs_\be_\bd, and _\bs_\be_\bt-_\bi_\bn-_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be.
Lastly, the function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn returns the
function argument.
8.4.3. internal structure
Currently, closures are implemented as vec-
tors, with property being the symbol fclosure. The
functional object is the first entry. The remain-
ing entries are structures which point to the sym-
bols and values for the closure, (with a reference
count to determine if a recursive closure is
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-11
active).
8.5. foreign subroutines and functions
FRANZ LISP has the ability to dynamically load
object files produced by other compilers and to call
functions defined in those files. These functions are
called _\bf_\bo_\br_\be_\bi_\bg_\bn functions.* There are seven types of
foreign functions. They are characterized by the type
of result they return, and by differences in the
interpretation of their arguments. They come from two
families: a group suited for languages which pass
arguments by reference (e.g. Fortran), and a group
suited for languages which pass arguments by value
(e.g. C).
There are four types in the first group:
subroutine
This does not return anything. The Lisp system
always returns t after calling a subroutine.
function
This returns whatever the function returns. This
must be a valid Lisp object or it may cause the
Lisp system to fail.
integer-function
This returns an integer which the Lisp system
makes into a fixnum and returns.
real-function
This returns a double precision real number which
the Lisp system makes into a flonum and returns.
There are three types in the second group:
c-function
This is like an integer function, except for its
different interpretation of arguments.
____________________
\e9 *This topic is also discussed in Report PAM-124 of the
Center for Pure and Applied Mathematics, UCB, entitled
``Parlez-Vous Franz? An Informal Introduction to Interfac-
ing Foreign Functions to Franz LISP'', by James R. Larus
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-12
double-c-function
This is like a real-function.
vector-c-function
This is for C functions which return a structure.
The first argument to such functions must be a
vector (of type vectori), into which the result
is stored. The second Lisp argument becomes the
first argument to the C function, and so on
A foreign function is accessed through a binary object
just like a compiled Lisp function. The difference is
that the discipline field of a binary object for a
foreign function is a string whose first character is
given in the following table:
\e8 ____________________________
letter type
\e8 ____________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b____________________________
s subroutine
\e8 ____________________________
f function
\e8 ____________________________
i integer-function
\e8 ____________________________
r real-function.
\e8 ____________________________
c c-function
\e8 ____________________________
v vector-c-function
\e8 ____________________________
d double-c-function
\e8 ____________________________
\e7 |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
Two functions are provided for setting-up foreign
functions. _\bC_\bf_\ba_\bs_\bl loads an object file into the Lisp
system and sets up one foreign function binary object.
If there are more than one function in an object file,
_\bg_\be_\bt_\ba_\bd_\bd_\br_\be_\bs_\bs can be used to set up additional foreign
function objects.
Foreign functions are called just like other
functions, e.g (_\bf_\bu_\bn_\bn_\ba_\bm_\be _\ba_\br_\bg_\b1 _\ba_\br_\bg_\b2). When a function
in the Fortran group is called, the arguments are
evaluated and then examined. List, hunk and symbol
arguments are passed unchanged to the foreign func-
tion. Fixnum and flonum arguments are copied into a
temporary location and a pointer to the value is
passed (this is because Fortran uses call by reference
and it is dangerous to modify the contents of a fixnum
or flonum which something else might point to). If
the argument is an array object, the data field of the
array object is passed to the foreign function (This
is the easiest way to send large amounts of data to
and receive large amounts of data from a foreign func-
tion). If a binary object is an argument, the entry
\e9 Printed: January 31, 1984
Functions, Fclosures, and Macros 8-13
field of that object is passed to the foreign function
(the entry field is the address of a function, so this
amounts to passing a function as an argument).
When a function in the C group is called, fixnum
and flownum arguments are passed by value. For almost
all other arguments, the address is merely provided to
the C routine. The only exception arises when you
want to invoke a C routine which expects a ``struc-
ture'' argument. Recall that a (rarely used) feature
of the C language is the ability to pass structures by
value. This copies the structure onto the stack.
Since the Franz's nearest equivalent to a C structure
is a vector, we provide an escape clause to copy the
contents of an immediate-type vector by value. If the
property field of a vectori argument, is the symbol
"value-structure-argument", then the binary data of
this immediate-type vector is copied into the argument
list of the C routine.
The method a foreign function uses to access the
arguments provided by Lisp is dependent on the
language of the foreign function. The following
scripts demonstrate how how Lisp can interact with
three languages: C, Pascal and Fortran. C and Pascal
have pointer types and the first script shows how to
use pointers to extract information from Lisp objects.
There are two functions defined for each language.
The first (cfoo in C, pfoo in Pascal) is given four
arguments, a fixnum, a flonum-block array, a hunk of
at least two fixnums and a list of at least two fix-
nums. To demonstrate that the values were passed,
each ?foo function prints its arguments (or parts of
them). The ?foo function then modifies the second
element of the flonum-block array and returns a 3 to
Lisp. The second function (cmemq in C, pmemq in Pas-
cal) acts just like the Lisp _\bm_\be_\bm_\bq function (except it
won't work for fixnums whereas the lisp _\bm_\be_\bm_\bq will work
for small fixnums). In the script, typed input is in
bold, computer output is in roman and comments are in
_\bi_\bt_\ba_\bl_\bi_\bc.
____________________________________________________________
_\bT_\bh_\be_\bs_\be _\ba_\br_\be _\bt_\bh_\be _\bC _\bc_\bo_\bd_\be_\bd _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs
% cat ch8auxc.c
/* demonstration of c coded foreign integer-function */
/* the following will be used to extract fixnums out of a list of fixnums */
struct listoffixnumscell
{ struct listoffixnumscell *cdr;
int *fixnum;
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-14
};
struct listcell
{ struct listcell *cdr;
int car;
};
cfoo(a,b,c,d)
int *a;
double b[];
int *c[];
struct listoffixnumscell *d;
{
printf("a: %d, b[0]: %f, b[1]: %f0, *a, b[0], b[1]);
printf(" c (first): %d c (second): %d0,
*c[0],*c[1]);
printf(" ( %d %d ... ) ", *(d->fixnum), *(d->cdr->fixnum));
b[1] = 3.1415926;
return(3);
}
struct listcell *
cmemq(element,list)
int element;
struct listcell *list;
{
for( ; list && element != list->car ; list = list->cdr);
return(list);
}
_\bT_\bh_\be_\bs_\be _\ba_\br_\be _\bt_\bh_\be _\bP_\ba_\bs_\bc_\ba_\bl _\bc_\bo_\bd_\be_\bd _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs
% cat ch8auxp.p
type pinteger = ^integer;
realarray = array[0..10] of real;
pintarray = array[0..10] of pinteger;
listoffixnumscell = record
cdr : ^listoffixnumscell;
fixnum : pinteger;
end;
plistcell = ^listcell;
listcell = record
cdr : plistcell;
car : integer;
end;
function pfoo ( var a : integer ;
var b : realarray;
var c : pintarray;
var d : listoffixnumscell) : integer;
begin
writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]);
writeln(' c (first):', c[0]^,' c (second):', c[1]^);
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-15
writeln(' ( ', d.fixnum^, d.cdr^.fixnum^, ' ...) ');
b[1] := 3.1415926;
pfoo := 3
end ;
{ the function pmemq looks for the Lisp pointer given as the first argument
in the list pointed to by the second argument.
Note that we declare " a : integer " instead of " var a : integer " since
we are interested in the pointer value instead of what it points to (which
could be any Lisp object)
}
function pmemq( a : integer; list : plistcell) : plistcell;
begin
while (list <> nil) and (list^.car <> a) do list := list^.cdr;
pmemq := list;
end ;
_\bT_\bh_\be _\bf_\bi_\bl_\be_\bs _\ba_\br_\be _\bc_\bo_\bm_\bp_\bi_\bl_\be_\bd
% cc -c ch8auxc.c
1.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
% pc -c ch8auxp.p
3.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w
% lisp
Franz Lisp, Opus 38.60
_\bF_\bi_\br_\bs_\bt _\bt_\bh_\be _\bf_\bi_\bl_\be_\bs _\ba_\br_\be _\bl_\bo_\ba_\bd_\be_\bd _\ba_\bn_\bd _\bw_\be _\bs_\be_\bt _\bu_\bp _\bo_\bn_\be _\bf_\bo_\br_\be_\bi_\bg_\bn _\bf_\bu_\bn_\bc_\b-
_\bt_\bi_\bo_\bn _\bb_\bi_\bn_\ba_\br_\by. _\bW_\be _\bh_\ba_\bv_\be _\bt_\bw_\bo _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bi_\bn _\be_\ba_\bc_\bh _\bf_\bi_\bl_\be _\bs_\bo _\bw_\be _\bm_\bu_\bs_\bt
_\bc_\bh_\bo_\bo_\bs_\be _\bo_\bn_\be _\bt_\bo _\bt_\be_\bl_\bl _\bc_\bf_\ba_\bs_\bl _\ba_\bb_\bo_\bu_\bt. _\bT_\bh_\be _\bc_\bh_\bo_\bi_\bc_\be _\bi_\bs _\ba_\br_\bb_\bi_\bt_\br_\ba_\br_\by.
-> (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")
/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0 -lc
#63000-"integer-function"
-> (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")
/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
#63200-"integer-function"
_\bH_\be_\br_\be _\bw_\be _\bs_\be_\bt _\bu_\bp _\bt_\bh_\be _\bo_\bt_\bh_\be_\br _\bf_\bo_\br_\be_\bi_\bg_\bn _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn _\bb_\bi_\bn_\ba_\br_\by _\bo_\bb_\bj_\be_\bc_\bt_\bs
-> (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")
#6306c-"function"
_\bW_\be _\bw_\ba_\bn_\bt _\bt_\bo _\bc_\br_\be_\ba_\bt_\be _\ba_\bn_\bd _\bi_\bn_\bi_\bt_\bi_\ba_\bl_\bi_\bz_\be _\ba_\bn _\ba_\br_\br_\ba_\by _\bt_\bo _\bp_\ba_\bs_\bs _\bt_\bo _\bt_\bh_\be
_\bc_\bf_\bo_\bo _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn. _\bI_\bn _\bt_\bh_\bi_\bs _\bc_\ba_\bs_\be _\bw_\be _\bc_\br_\be_\ba_\bt_\be _\ba_\bn _\bu_\bn_\bn_\ba_\bm_\be_\bd _\ba_\br_\br_\ba_\by _\ba_\bn_\bd
_\bs_\bt_\bo_\br_\be _\bi_\bt _\bi_\bn _\bt_\bh_\be _\bv_\ba_\bl_\bu_\be _\bc_\be_\bl_\bl _\bo_\bf _\bt_\be_\bs_\bt_\ba_\br_\br. _\bW_\bh_\be_\bn _\bw_\be _\bc_\br_\be_\ba_\bt_\be _\ba_\bn
_\ba_\br_\br_\ba_\by _\bt_\bo _\bp_\ba_\bs_\bs _\bt_\bo _\bt_\bh_\be _\bP_\ba_\bs_\bc_\ba_\bl _\bp_\br_\bo_\bg_\br_\ba_\bm _\bw_\be _\bw_\bi_\bl_\bl _\bu_\bs_\be _\ba _\bn_\ba_\bm_\be_\bd
_\ba_\br_\br_\ba_\by _\bj_\bu_\bs_\bt _\bt_\bo _\bd_\be_\bm_\bo_\bn_\bs_\bt_\br_\ba_\bt_\be _\bt_\bh_\be _\bd_\bi_\bf_\bf_\be_\br_\be_\bn_\bt _\bw_\ba_\by _\bt_\bh_\ba_\bt _\bn_\ba_\bm_\be_\bd _\ba_\bn_\bd
_\bu_\bn_\bn_\ba_\bm_\be_\bd _\ba_\br_\br_\ba_\by_\bs _\ba_\br_\be _\bc_\br_\be_\ba_\bt_\be_\bd _\ba_\bn_\bd _\ba_\bc_\bc_\be_\bs_\bs_\be_\bd.
-> (setq testarr (array nil flonum-block 2))
array[2]
-> (store (funcall testarr 0) 1.234)
1.234
-> (store (funcall testarr 1) 5.678)
5.678
-> (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))
a: 385, b[0]: 1.234000, b[1]: 5.678000
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-16
c (first): 10 c (second): 11
( 15 16 ... )
3
_\bN_\bo_\bt_\be _\bt_\bh_\ba_\bt _\bc_\bf_\bo_\bo _\bh_\ba_\bs _\br_\be_\bt_\bu_\br_\bn_\be_\bd _\b3 _\ba_\bs _\bi_\bt _\bs_\bh_\bo_\bu_\bl_\bd. _\bI_\bt _\ba_\bl_\bs_\bo _\bh_\ba_\bd _\bt_\bh_\be
_\bs_\bi_\bd_\be _\be_\bf_\bf_\be_\bc_\bt _\bo_\bf _\bc_\bh_\ba_\bn_\bg_\bi_\bn_\bg _\bt_\bh_\be _\bs_\be_\bc_\bo_\bn_\bd _\bv_\ba_\bl_\bu_\be _\bo_\bf _\bt_\bh_\be _\ba_\br_\br_\ba_\by _\bt_\bo
_\b3._\b1_\b4_\b1_\b5_\b9_\b2_\b6 _\bw_\bh_\bi_\bc_\bh _\bc_\bh_\be_\bc_\bk _\bn_\be_\bx_\bt.
-> (funcall testarr 1)
3.1415926
_\bI_\bn _\bp_\br_\be_\bp_\ba_\br_\ba_\bt_\bi_\bo_\bn _\bf_\bo_\br _\bc_\ba_\bl_\bl_\bi_\bn_\bg _\bp_\bf_\bo_\bo _\bw_\be _\bc_\br_\be_\ba_\bt_\be _\ba_\bn _\ba_\br_\br_\ba_\by.
-> (array test flonum-block 2)
array[2]
-> (store (test 0) 1.234)
1.234
-> (store (test 1) 5.678)
5.678
-> (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))
a: 385 b[0]: 1.23400000000000E+00 b[1]: 5.67800000000000E+00
c (first): 10 c (second): 11
( 15 16 ...)
3
-> (test 1)
3.1415926
_\bN_\bo_\bw _\bt_\bo _\bt_\be_\bs_\bt _\bo_\bu_\bt _\bt_\bh_\be _\bm_\be_\bm_\bq'_\bs
-> (cmemq 'a '(b c a d e f))
(_\ba _\bd _\be _\bf)
-> (pmemq 'e '(a d f g a x))
_\bn_\bi_\bl
____________________________________________________________
The Fortran example will be much shorter since in
Fortran you can't follow pointers as you can in other
languages. The Fortran function ffoo is given three
arguments: a fixnum, a fixnum-block array and a flo-
num. These arguments are printed out to verify that
they made it and then the first value of the array is
modified. The function returns a double precision
value which is converted to a flonum by lisp and
printed. Note that the entry point corresponding to
the Fortran function ffoo is _ffoo_ as opposed to the
C and Pascal convention of preceding the name with an
underscore.
____________________________________________________________
% cat ch8auxf.f
Printed: January 31, 1984
Functions, Fclosures, and Macros 8-17
double precision function ffoo(a,b,c)
integer a,b(10)
double precision c
print 2,a,b(1),b(2),c
2 format(' a=',i4,', b(1)=',i5,', b(2)=',i5,' c=',f6.4)
b(1) = 22
ffoo = 1.23456
return
end
% f77 -c ch8auxf.f
ch8auxf.f:
ffoo:
0.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
% lisp
Franz Lisp, Opus 38.60
-> (cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")
/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxf.o -e _ffoo_
-o /tmp/Li11066.0 -lF77 -lI77 -lc
#6307c-"real-function"
-> (array test fixnum-block 2)
array[2]
-> (store (test 0) 10)
10
-> (store (test 1) 11)
11
-> (ffoo 385 (getd 'test) 5.678)
a= 385, b(1)= 10, b(2)= 11 c=5.6780
1.234559893608093
-> (test 0)
22
____________________________________________________________
\e9
\e9 Printed: January 31, 1984