4.1cBSD/usr/doc/lisp/ch8.n

." @(#)ch8.n	34.1 1/29/81
.Lc Functions\ and\ Macros 8
.sh 2 valid\ function\ objects 8
.pp
There are many different objects which can occupy the function field of 
a symbol object.
The following table shows all of the possibilities, how to recognize them
and where to look for documentation.
.sp 2v
.TS
box center ;
c | c | c .
informal name	object type	documentation 
=
interpreted	list with \fIcar\fP	8.2
lambda function	\fIeq\fP to lambda
_
interpreted	list with \fIcar\fP	8.2
nlambda function	\fIeq\fP to nlambda
_
interpreted	list with \fIcar\fP	8.2
lexpr function	\fIeq\fP to lexpr
_
interpreted	list with \fIcar\fP	8.3
macro	\fIeq\fP to macro
_
compiled	binary with discipline	8.2
lambda or lexpr	\fIeq\fP to lambda
function
_
compiled	binary with discipline	8.2
nlambda function	\fIeq\fP to nlambda
_
compiled	binary with discipline	8.3
macro	\fIeq\fP to macro
_
foreign	binary with discipline	8.4
subroutine	of "subroutine"\*[\(dg\*]
_
foreign	binary with discipline	8.4
function	of "function"\*[\(dg\*]
_
foreign	binary with discipline	8.4
integer function	of "integer-function"\*[\(dg\*]
_
foreign	binary with discipline	8.4
real function	of "real-function"\*[\(dg\*]
_
array	array object	9
.TE
.sh 2 functions
The basic lisp function is the lambda function.
.(f
\*[\(dg\*]Only the first character of the string is significant (i.e "s"
is ok for "subroutine")
.)f
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.
.pp
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 \fIcond\fP, \fIdo\fP, \fIor\fP).
When an nlambda function is called, the list of unevaluated arguments
is lambda bound to the single formal parameter of the nlambda function.
.pp
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 \fIeval\fP over
the list of unevaluated arguments it has been passed.
This is usually the wrong thing to do as it won't 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 the number of arguments is lambda-bound to the single
formal parameter of the lexpr function.
The lexpr then accesses the arguments using the \fIarg\fP function.
.pp
When a function is compiled 
.i special 
declaration 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 
.i special 
(see \(sc12.3.2.2).
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.
.sh 2 macros
An important features 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 Pascal) 
and refer to elements of those records by the key names.\*[\(dg\*]
.(f
\*[\(dg\*]A record definition macro package especially suited for
.Fr
is in the planning stages at Berkeley.
At this time
the Maclisp
.i struct 
package can be used.
.)f
Another  popular use for macros is to create more readable control 
structures which expand into 
.i cond , 
.i or 
and 
.i and .
One such example is the If macro in the jkfmacs.l package.
It allows you to write
.sp 1v
.nf
.ft I
(If (equal numb 0) then (print 'zero) (terpr)
\ elseif (equal numb 1) then (print 'one) (terpr)
\ else (print '|I give up|))
.ft P
.sp 1v
which expands to 
.sp 1v
.ft I
(cond 
\ \ \ \ ((equal numb 0) (print 'zero) (terpr))
\ \ \ \ ((equal numb 1) (print 'one) (terpr))
\ \ \ \ (t (print '|I give up|)))
.ft P
.sp 1v
.fi
.sh 3  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:
.sp 1v
.nf
-> \fI(def first (macro (x) (cons 'car (cdr x))))\fP
first
-> \fI(first '(a b c))\fP
a
-> \fI(apply 'first '(first '(a b c)))\fP
(car '(a b c))
.fi
.sp 1v
The first input line defines a macro called 
.i first .
Notice that the macro has one formal parameter, \fIx\fP.  
On the second input line, we ask the interpreter to evaluate
\fI(first\ '(a\ b\ c))\fP.
.i Eval 
sees that 
.i first
has a function definition of type macro  so it evaluates 
.i first 's 
definition
passing to 
.i first 
as an argument, the form 
.i eval 
itself
was trying to
evaluate, \fI(first\ '(a\ b\ c))\fP.
The 
.i first 
macro chops off the car of the argument with
.i cdr ,
cons' a 
.i car
at the beginning of the list and returns \fI(car\ '(a\ b\ c))\fP.
Now 
.i eval 
evaluates that, and the value is
.i a
which is returned as the value of \fI(first\ '(a\ b\ c))\fP.
Thus whenever 
.i eval
tries to evaluate a list whose car has a macro definition
it ends up doing (at least) two operations, one 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 
.i eval
may have to do even more evaluations until it can finally determine
the  value of an expression.
One way to see how a macro will expand is to use
.i apply
as shown on the third input line above.
.sh +0 defmacro
The macro 
.i defmacro
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
\fI(setq\ stack\ (cons\ newelt\ stack)\fP.
We could define a macro named \fIpush\fP to do this for us.
One way to define it is:
.nf
.sp 1v
-> \fI(def push (macro (x) (list 'setq (caddr x) (list 'cons (cadr x) (caddr x)))))\fP
push
.fi
.sp 1v
then \fI(push\ newelt\ stack)\fP will expand to the form mentioned above.
The same macro written using defmacro would be:
.nf
.sp 1v
-> \fI(defmacro push (value stack) (list 'setq stack (list 'cons value stack))\fP
push
.fi
.sp 1v
Defmacro allows you to name the arguments of the macro call, and makes the 
macro definition look more like a function definition.
.sh +0 the\ backquote\ character\ macro
The default syntax for 
.Fr
has only three characters with associated character macros.
One is semicolon for comments.
The other two are backquote and comma which are used by the backquote character
macro.
The backquote macro is used to create lists where many of the elements are
fixed (quoted). 
This makes it very useful for creating macro definitions.
In the simplest case, a backquote acts just like a single quote:
.sp 1v
.nf
->\fI`(a b c d e)\fP
(a b c d e)
.fi
.sp 1v
If a comma precedes an element of a backquoted list then that element is
evaluated and its value is put in the list.
.sp 1v
.nf
->\fI(setq d '(x y z))\fP
(x y z)
->\fI`(a b c ,d e)\fP
(a b c (x y z) e)
.fi
.sp 1v
If a comma followed by an at sign precedes an element in a backquoted list,
then that element is evaluated and spliced into the list with 
.i append .
.nf
.sp 1v
->\fI`(a b c ,@d e)\fP
(a b c x y z e)
.sp 1v
.fi
Once a list begins with a backquote, the commas may appear anywhere in the
list as this example shows:
.nf
.sp 1v
->\fI`(a b (c d ,(cdr d)) (e f (g h ,@(cddr d) ,@d)))\fP
(a b (c d (y z)) (e f (g h z x y z)))
.sp 1v
.fi
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.
.sp 1v
.nf
->\fI(defmacro first (list) `(car ,list))\fP
first
->\fI(defmacro push (value stack) `(setq ,stack (cons ,value ,stack)))\fP
stack
.fi
.sh 2 foreign\ subroutines\ and\ functions
.Fr 
has the ability to dynamically load object files produced by other compilers
and then call functions defined in those files.
These functions are called 
.i foreign
functions.
There are four types of foreign functions and they are characterized by
the type of result they return:
.ip subroutine  
This does not return anything. 
The lisp system
always returns t after calling a subroutine.
.ip function
This returns whatever the function returns.
This must be a valid lisp object or it may cause the lisp system to fail.
.ip integer-function
This returns an integer which the lisp system makes into a fixnum and returns.
.ip real-function
This returns a double precision real number which the lisp
system makes into a flonum and returns.
.lp
A foreign function is accessed through a binary object just like a 
compiled lisp function.
The difference is that the discipline field for a binary object
of a foreign function is a string 
whose first character is s for a subroutine,
f for a function, i for an integer-function and r for a real-function.
Two functions are provided for the setting up of foreign functions.
.i Cfasl
loads an object file into the lisp system and sets up one foreign
function binary object.
If there is more than one function in an object file, 
.i getaddress
can be used to set up further foreign function objects.
.pp
Foreign  functions are called just like other functions, e.g 
\fI(funname\ arg1\ arg2)\fP.
When one is called, the arguments are evaluated and then examined.
List, hunk and symbol arguments are passed unchanged to 
the foreign function.
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 an array object is an argument 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
function).
If a binary object is an argument, the entry 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).
.pp
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 is 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 fixnums.
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 Pascal) acts just like the
lisp
.i memq
function (except it won't work for fixnums whereas the lisp 
.i memq
will work for small fixnums).
In the script, typed input is in 
.b bold ,
computer output is in roman
and comments are in
.i italic.
.nf
.sp 2v
\fIThese are the C coded functions  \fP
% \fBcat ch8auxc.c\fP
/* 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;
};

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]: %f\n", *a, b[0], b[1]);
    printf(" c (first): %d   c (second): %d\n",
	       *c[0],*c[1]);
    printf(" ( %d %d ... )\n ", *(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);
}
.sp 2v
\fIThese are the Pascal coded functions \fP
% \fBcat ch8auxp.p\fP
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]^);
   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 ;
.sp 2v
\fIThe files are compiled\fP
% \fBcc -c ch8auxc.c\fP
1.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
% \fBpc -c ch8auxp.p\fP
3.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w
.sp 2v
% \fBlisp\fP
Franz Lisp, Opus 33b
.ft I
.fi
First the files are loaded and we set up one foreign function binary.
We have two functions in each file so we must choose one to tell cfasl about.
The choice is arbitrary.
.ft P
.br 
.nf
->\fB (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")\fP
/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0  -lc
#63000-"integer-function"
->\fB (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")\fP
/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
#63200-"integer-function"
.ft I
Here we set up the other foreign function binary objects
.ft P
->\fB (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")\fP
#6306c-"function"
.ft I
.fi
We want to create and initialize an array to pass to the cfoo function.
In this case we create an unnamed array and store it in the value cell of
testarr. 
When we create an array to pass to the Pascal program we will used a named
array just to demonstrate the different way that named and unnamed arrays
are created and accessed.
.br
.nf
.ft P
->\fB (setq testarr (array nil flonum-block 2))\fP
array[2]
->\fB (store (funcall testarr 0) 1.234)\fP
1.234
->\fB (store (funcall testarr 1) 5.678)\fP
5.678
->\fB (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))\fP
a: 385, b[0]: 1.234000, b[1]: 5.678000
 c (first): 10   c (second): 11
 ( 15 16 ... )
 3
.ft I
.fi
Note that cfoo has returned 3 as it should.
It also had the side effect of changing the second value of the array to
3.1415926  which check next.
.br
.nf
.ft P
->\fB (funcall testarr 1)\fP
3.1415926
.sp 2v
.fi
.ft I
In preparation for calling pfoo we create an array.
.ft P
.nf
->\fB (array test flonum-block 2)\fP
array[2]
->\fB (store (test 0) 1.234)\fP
1.234
->\fB (store (test 1) 5.678)\fP
5.678
->\fB (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))\fP
 a:       385 b[0]:  1.23400000000000E+00 b[1]:  5.67800000000000E+00
 c (first):        10 c (second):        11
 (         15        16 ...) 
3
->\fB (test 1)\fP
3.1415926
.sp 1v
\fI Now to test out the memq's
-> \fB(cmemq 'a '(b c a d e f))\fP
(a d e f)
-> \fB(pmemq 'e '(a d f g a x))\fP
nil
.fi
.pp
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 flonum.
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.
.sp 1v
.nf

% \fBcat ch8auxf.f\fP
	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
% \fBf77 -c ch8auxf.f\fP
ch8auxf.f:
   ffoo:
0.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
% \fBlisp\fP
Franz Lisp, Opus 33b
-> \fB(cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")\fP
/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"
.sp 1v
-> \fB(array test fixnum-block 2)\fP
array[2]
->\fB (store (test 0) 10)\fP
10
-> \fB(store (test 1) 11)\fP
11
-> \fB(ffoo 385 (getd 'test) 5.678)\fP
 a= 385, b(1)=   10, b(2)=   11 c=5.6780
1.234559893608093
-> \fB(test 0)\fP
22