That's probably the new property list functions done...
but too tired to test!
This commit is contained in:
parent
31d8f0b8f9
commit
64a27be8e5
354
doc/lisp1.5.md
354
doc/lisp1.5.md
|
@ -331,7 +331,7 @@ it is not A.
|
|||
|
||||
The main application of conditional expressions is in defining functions recursively.
|
||||
|
||||
#### Example
|
||||
#### Example - recursive function
|
||||
|
||||
`ff[x] = [atom[x] -> x; T -> ff[car[x]]]`
|
||||
|
||||
|
@ -373,7 +373,7 @@ The conditional expression is useful for defining numerical computations, as wel
|
|||
```
|
||||
|x| = [x<0 -> -x; T -> x]
|
||||
```
|
||||
The factorial of a nonhnegative integer can be defined by
|
||||
The factorial of a non-negative integer can be defined by
|
||||
```
|
||||
n! = [n=0 -> 1; T -> n.[n-l]!]
|
||||
```
|
||||
|
@ -569,26 +569,32 @@ This can be translated into the following S-expression: ,
|
|||
((QUOTE T)(QUOTE F)))))
|
||||
```
|
||||
|
||||
- sub st[^;^; z]
|
||||
This function gives the result of substituting the S-expression x for all occurrences
|
||||
of the atomic symbol y in the S-expression z. It is defined by
|
||||
#### subst[x; y; z]
|
||||
|
||||
###### s~bst[x;~;z] = [eq~al[~;z] -- x;atom[z] - z;T - cons[subst
|
||||
This function gives the result of substituting the S-expression x for all occurrences of the atomic symbol y in the S-expression z. It is defined by
|
||||
|
||||
```
|
||||
subst[x; y; z] = [equal[y; z] -> x;
|
||||
atom[z] - z;
|
||||
T - cons[subst
|
||||
[x; y; car[z]]; subst[x; y; cdr[z]]]]
|
||||
```
|
||||
|
||||
As an example, we have
|
||||
|
||||
SU~S~[(X. A);B;((A. B). c)] = ((A. (X. A)). C)
|
||||
null[x]
|
||||
This predicate is useful for deciding when a list is exhausted. It is true if and
|
||||
only if its argument is NIL.
|
||||
```lisp
|
||||
SUBST[(X . A); B; ((A . B) . c)] = ((A . (X . A)) . C)
|
||||
```
|
||||
|
||||
#### null[x]
|
||||
This predicate is useful for deciding when a list is exhausted. It is true if and only if its argument is NIL.
|
||||
|
||||
The following functions are useful when S-expressions are regarded as lists.
|
||||
|
||||
1. append[x; y]
|
||||
append[x; y] = [n~ll[x]-~; T-cons[car [x]; append[cdr [x]; y I]]
|
||||
#### 1. append[x; y]
|
||||
```
|
||||
append[x; y] = [null[x] -> y; T -> cons[car [x]; append[cdr [x]; y]]]
|
||||
```
|
||||
|
||||
An example is
|
||||
|
||||
|
@ -596,175 +602,193 @@ An example is
|
|||
append[(A B);(C D E)] = (A B C D E)
|
||||
```
|
||||
|
||||
2. member[^;^]
|
||||
This predicate is true if the S-expression x occurs among the elements of the
|
||||
list y. We have
|
||||
memberlx; y] = [null[y ]--F;
|
||||
equal[x; car [y ]I--T;
|
||||
T-member [x; cdr [y I]]
|
||||
#### 2. member[x; y]
|
||||
|
||||
This function gives the list of pairs of corresponding elements of the lists x and
|
||||
y, and appends this to the list a. The resultant list of pairs, which is like a table with
|
||||
This predicate is true if the S-expression `x` occurs among the elements of the list `y`. We have
|
||||
```
|
||||
member[x; y] = [null[y] -> F;
|
||||
equal[x; car [y ]] ->T;
|
||||
T -> member[x; cdr [y ]]]
|
||||
```
|
||||
|
||||
#### 3. pairlis[x; y; a]
|
||||
|
||||
<a name="page12">page 12</a>
|
||||
|
||||
This function gives the list of pairs of corresponding elements of the lists `x` and
|
||||
`y`, and appends this to the list `a`. The resultant list of pairs, which is like a table with
|
||||
two columns, is called an association list. We have
|
||||
|
||||
```
|
||||
pairlis [x; y; a] = [null[x]--a; T-cons[cons[car[x]; car[y]];
|
||||
pairlis [x; y; a] = [null[x] -> a;
|
||||
T -> cons[cons[car[x]; car[y]];
|
||||
pairlis[cdr[x]; cdr [y]; a]]]
|
||||
```
|
||||
|
||||
An example is
|
||||
|
||||
```
|
||||
pairlis[(A B C);(U V w);((D. X) (E. Y))] =
|
||||
pairlis[(A B C);(U V W);((D . X) (E . Y))] =
|
||||
((A . U) (B . V) (C . W)(D . X) (E . Y))
|
||||
```
|
||||
|
||||
4. assoc[x; a]
|
||||
If a is an association list such as the one formed by pairlis in the above example,
|
||||
then assoc will produce the first pair whose first term is x. Thus it is a table searching
|
||||
#### 4. assoc[x; a]
|
||||
|
||||
If `a` is an association list such as the one formed by `pairlis` in the above example,
|
||||
then `assoc` will produce the first pair whose first term is `x`. Thus it is a table searching
|
||||
function. We have
|
||||
|
||||
```
|
||||
assoc[x; a] = [equal[caar[a]; x] -> car[a]; T -> assoc[x; cdr[a]]]
|
||||
```
|
||||
|
||||
An example is
|
||||
|
||||
```
|
||||
assoc[~;((A. (M N)), (B. (CAR X)), (C. (QUOTE M)), (C. (CDR x)))]
|
||||
= (B. (CAR x))
|
||||
assoc[B; ((A . (M N)), (B . (CAR X)), (C . (QUOTE M)), (C . (CDR x)))]
|
||||
= (B . (CAR X))
|
||||
```
|
||||
|
||||
5. sublisla; y]
|
||||
Here a is assumed to be an association list of the form ((ul. vl)... (un. v,)),
|
||||
where the u1 s are atomic, and y is any S-expression. What sublis does, is to treat
|
||||
the u1 s as variables when they occur in y, and to substitute the corresponding v1 s
|
||||
from the pair list. In order to define sublis, we first define an auxiliary function.
|
||||
We have
|
||||
sub2[a; z] = [null[a]+z;eq[caar[a]; z]-cdar[a];~-
|
||||
sub%[cdr[a]; z]]
|
||||
##### 5. sublis[a; y]
|
||||
|
||||
Here `a` is assumed to be an association list of the form ((u<sub>1</sub>. v<sub>1</sub>)... (u<sub>n</sub> . v<sub>n</sub>)),
|
||||
where the `u`s are atomic, and `y` is any S-expression. What `sublis` does, is to treat
|
||||
the `u`s as variables when they occur in `y`, and to substitute the corresponding `v`s
|
||||
from the pair list. In order to define `sublis`, we first define an auxiliary function. We have
|
||||
|
||||
```
|
||||
sub2[a; z] = [null[a] -> z; eq[caar[a]; z] -> cdar[a];
|
||||
T -> sub2[cdr[a]; z]]
|
||||
```
|
||||
and
|
||||
sublis[a; y] = [at0rn[~]-sub2[a;~]; T-cons[sublis[a; car[^]];
|
||||
sublis[a; cdr [Y]]]]
|
||||
|
||||
```
|
||||
sublis[a; y] = [atom[y] -> sub2[a; y];
|
||||
T -> cons[sublis[a; car[y]]; sublis[a; cdr[y]]]]
|
||||
```
|
||||
|
||||
An example is
|
||||
|
||||
```
|
||||
sublis[((X. SHAKESPEARE) (Y. (THE TEMPEST)));(X WROTE Y)] =
|
||||
(SHAKESPEARE WROTE (THE TEMPEST))
|
||||
The universal function evalquote that is about to be defined obeys the following
|
||||
identity. Let f be a function written as an M-expression, and let fn be its translation.
|
||||
(& is an S-expression. ) Let f be a function of n arguments and let args=(argl...
|
||||
argn), a list of the n S-expressions being used as arguments. Then
|
||||
|
||||
```
|
||||
|
||||
The universal function `evalquote` that is about to be defined obeys the following identity. Let `f` be a function written as an M-expression, and let `fn` be its translation. (`fn` is an S-expression. ) Let `f` be a function of n arguments and let args=(arg<sub>1</sub>... arg<sub>n</sub>), a list of the `n` S-expressions being used as arguments. Then
|
||||
|
||||
`evalquote[fn; args] = f[arg`<sub>1</sub>`... arg`<sub>n</sub>`]`
|
||||
|
||||
<a name="page13">page 13</a>
|
||||
|
||||
if either side of the equation is defined at all.
|
||||
|
||||
Example
|
||||
fi ~[[x;~];cons[car[x];y]]
|
||||
fn: (LAMBDA (X Y) (CONS (CAR X) Y))
|
||||
argl: (A B)
|
||||
arg2: (C D)
|
||||
args: ((A B) (C D))
|
||||
evalquote[(LAMBDA (X Y) (CONS (CAR X) Y)); ((A B) (C D))] =
|
||||
~[[x;y];cons[car[x];y]][(A B);(C Dl]=
|
||||
(A C D)
|
||||
evalquote is defined by using two main functions, called eval and apply. apply
|
||||
handles a function and its arguments, while eval handles forms. Each of these func-
|
||||
tions also has another argument that is used as an association list for storing the val-
|
||||
ues of bound variables and f unction names.
|
||||
|
||||
| | |
|
||||
| --------------- | -------------------------------- |
|
||||
| f | λ[[x; y];cons[car[x]; y]] |
|
||||
| fn | (LAMBDA (X Y) (CONS (CAR X) Y)) |
|
||||
| arg<sub>1</sub> | (A B) |
|
||||
| arg<sub>2</sub> | (C D) |
|
||||
| args | ((A B) (C D)) |
|
||||
|
||||
`evalquote[(LAMBDA (X Y) (CONS (CAR X) Y)); ((A B) (C D))] =`
|
||||
λ`[[x;y];cons[car[x];y]][(A B);(C D)] =`
|
||||
`(A C D)`
|
||||
|
||||
`evalquote` is defined by using two main functions, called `eval` and `apply`. `apply` handles a function and its arguments, while `eval` handles forms. Each of these functions also has another argument that is used as an association list for storing the values of bound variables and function names.
|
||||
|
||||
*note here that the environment -- the combination of the object list and the pushdown list -- is said to be an assoc list, where, importantly, it isn't. Of course, for the simplest possible Lisp, it would be -- But (to my surprise) Lisp 1.5 is nothing like the simplest possible Lisp.*
|
||||
|
||||
```mexpr
|
||||
evalquote[fn; x] = apply[fn; x; NIL]
|
||||
```
|
||||
|
||||
```
|
||||
where
|
||||
```mexpr
|
||||
apply[fn; x; a] =
|
||||
```
|
||||
|
||||
##### [atom[fn] - [eq[fn;~~~] - caar[x]
|
||||
|
||||
```
|
||||
eq[fn;~~~] -- cdar[x];
|
||||
eq[fn; CONS] -- cons[car[x]; cadr[x]];
|
||||
eq[fn;~~~~] -- atom[car[x]];
|
||||
eq[fn; EQ] - eq[car[x]; cadr[x]];
|
||||
```
|
||||
|
||||
###### T - apply[eval[fn;a];x;a]]
|
||||
|
||||
eq[car[fn]; LAMBDA] -- eval[caddr [fn]; pairlis[cadr[fn];x;a]];
|
||||
|
||||
###### eq[car [fn]; LABEL] - apply [caddr [fn]; x; cons [cons[cadr [fn]
|
||||
|
||||
```
|
||||
[atom[fn] -> [eq[fn; CAR] -> caar[x]
|
||||
eq[fn; CDR] -> cdar[x];
|
||||
eq[fn; CONS] -> cons[car[x]; cadr[x]];
|
||||
eq[fn; ATOM] -> atom[car[x]];
|
||||
eq[fn; EQ] -> eq[car[x]; cadr[x]];
|
||||
T -> apply[eval[fn; a]; x; a]]
|
||||
eq[car[fn]; LAMBDA] -> eval[caddr[fn]; pairlis[cadr[fn]; x; a]];
|
||||
eq[car[fn]; LABEL] -> apply[caddr [fn]; x; cons[cons[cadr [fn];
|
||||
caddr[fn]]; a]]]
|
||||
eval[e;a] = [atom[e] - cdr[assoc[e;a]];
|
||||
|
||||
eval[e;a] = [atom[e] -> cdr[assoc[e;a]];
|
||||
atom[car[e]] -> [eq[car[e]; QUOTE] -> cadr[e];
|
||||
eq[car[e]; COND] -> evcon[cdr[e]; a];
|
||||
T -> apply[car[e]; evlis[cdr[el; a]; a]];
|
||||
T -> apply[car[e]; evlis [cdr[e]; a]; a]]
|
||||
```
|
||||
|
||||
###### atom[car[e]] -
|
||||
`pairlis` and `assoc` have been previously defined.
|
||||
|
||||
```
|
||||
[eq[car QUOTE] - cadr [el;
|
||||
eq[car[e]; COND] - evcon[cdr [el; a];
|
||||
T -- apply[car [el; evlis[cdr [el; a]; a]];
|
||||
T - apply[car [el; evlis [cdr [el; a]; a]]
|
||||
```mexpr
|
||||
evcon[c; a] = [eval[caar[c]; a] -> eval[cadar[c]; a];
|
||||
T -> evcon[cdr [c];a]]
|
||||
```
|
||||
|
||||
pairlis and assoc have been previously defined.
|
||||
|
||||
```
|
||||
evcon[c; a] = [eval[caar [c]; a] -- eval[cadar [c]; a];
|
||||
T -- evcon[cdr [c];a]]
|
||||
and
|
||||
|
||||
```mexpr
|
||||
evlis[m; a] = [null[m] -> NIL;
|
||||
T -> cons [eval[car [m];a];evlis[cdr [m];a]]]
|
||||
```
|
||||
|
||||
###### evlis[m;a] = [null[m] - NIL
|
||||
|
||||
##### T - cons [eval[car [m];a];evlis[cdr [m];a]]]
|
||||
<a name="page14">page 14</a>
|
||||
|
||||
We shall explain a number of points about these definitions.
|
||||
The first argument for - apply is a function. If it is an atomic symbol, then there
|
||||
are two possibilities. One is that it is an elementary function: car, cdr, cons, eq,
|
||||
or atom. In each case, the appropriate function is applied to the argument(s). If it is
|
||||
not one of these, then its meaning has to be looked up in the association list.
|
||||
If it begins with LAMBDA, then the arguments are paired with the bound variables,
|
||||
and the form is given to -1 to evaluate.
|
||||
If it begins with LABEL, then the function name and definition are added to the as-
|
||||
sociation list, and the inside function is evaluated by apply.
|
||||
The first argument of is a form. If it is atomic, then it must be a variable,
|
||||
and its value is looked up on the association list.
|
||||
If =of the form is QUOTE, then it is a constant, and the value is cadr of the form
|
||||
itself.
|
||||
If car of the form is CGND, then it is a conditional expression, and evcon evaluates
|
||||
the propositional terms in order, and choses the form following the first true predicate.
|
||||
In all other cases, the form must be a function followed by its arguments. The ar-
|
||||
guments are then evaluated, and the function is given to apply.
|
||||
The LISP Programming System has many added features that have not been de-
|
||||
scribed thus far. These will be treated hereafter. At this point, it is worth noting the
|
||||
following points.
|
||||
|
||||
1. In the pure theory of LISP, all functions other than the five basic ones need to
|
||||
be defined each time they are to be used. This is unworkable in a practical sense.
|
||||
The LISP programming system has a larger stock of built-in functions known to the in-
|
||||
terpreter, and provision for adding as many more as the programmer cares to define.
|
||||
2. The basic functions car. and cdr were said to be undefined for atomic arguments.
|
||||
In the system, they always have a value, although it may not always be meaningful.
|
||||
Similarly, the basic predicate eq - always has a value. The effects of these functions
|
||||
The first argument for `apply` is a function. If it is an atomic symbol, then there are two possibilities. One is that it is an elementary function: `car`, `cdr`, `cons`, `eq`, or `atom`. In each case, the appropriate function is applied to the argument(s). If it is not one of these, then its meaning has to be looked up in the association list.
|
||||
|
||||
If it begins with `LAMBDA`, then the arguments are paired with the bound variables, and the form is given to `eval` to evaluate.
|
||||
|
||||
If it begins with `LABEL`, then the function name and definition are added to the as-
|
||||
sociation list, and the inside function is evaluated by apply.
|
||||
|
||||
The first argument of `eval` is a form. If it is atomic, then it must be a variable, and its value is looked up on the association list.
|
||||
|
||||
If `car` of the form is `QUOTE`, then it is a constant, and the value is `cadr` of the form
|
||||
itself.
|
||||
|
||||
If `car` of the form is `COND`, then it is a conditional expression, and `evcon` evaluates
|
||||
the propositional terms in order, and choses the form following the first true predicate.
|
||||
|
||||
In all other cases, the form must be a function followed by its arguments. The arguments are then evaluated, and the function is given to apply.
|
||||
|
||||
The LISP Programming System has many added features that have not been described thus far. These will be treated hereafter. At this point, it is worth noting the following points.
|
||||
|
||||
1. In the pure theory of LISP, all functions other than the five basic ones need to be defined each time they are to be used. This is unworkable in a practical sense. The LISP programming system has a larger stock of built-in functions known to the interpreter, and provision for adding as many more as the programmer cares to define.
|
||||
2. The basic functions `car` and `cdr` were said to be undefined for atomic arguments. In the system, they always have a value, although it may not always be meaningful.
|
||||
Similarly, the basic predicate `eq` always has a value. The effects of these functions
|
||||
in unusual cases will be understood after reading the chapter on list structures in the
|
||||
computer.
|
||||
3. Except for very unusual cases, one never writes (QUOTE T) or (QUOTE F),
|
||||
3. Except for very unusual cases, one never writes `(QUOTE T)` or `(QUOTE F)`,
|
||||
but T, and F respectively.
|
||||
4. There is provision in LISP for computing with fixed and floating point numbers.
|
||||
These are introduced as psuedo-atomic symbols.
|
||||
The reader is warned that the definitions of apply and ~l given above are pedagogi-
|
||||
cal devices and are not the same functions as those built into the LISP programming
|
||||
system. Appendix B contains the computer implemented version of these functions and
|
||||
should be used to decide questions about how things really work.
|
||||
4. There is provision in LISP for computing with fixed and floating point numbers. These are introduced as psuedo-atomic symbols.
|
||||
|
||||
11. THE LISP INTERPRETER SYSTEM
|
||||
The reader is warned that the definitions of `apply` and `eval` given above are pedagogical devices and are not the same functions as those built into the LISP programming system. Appendix B contains the computer implemented version of these functions and should be used to decide questions about how things really work.
|
||||
|
||||
The following example is a LISP program that defines three functions union, inter-
|
||||
section, and member, and then applies these functions to some test cases. The functions
|
||||
union and intersection are to be applied to "sets," each set being represented by a list
|
||||
of atomic symbols. The functions are defined as follows. Note that they are all recur-
|
||||
sive, and both union and intersection make use of member.
|
||||
<a name="page15">page 15</a>
|
||||
|
||||
## II. THE LISP INTERPRETER SYSTEM
|
||||
|
||||
The following example is a LISP program that defines three functions `union`, `intersection`, and `member`, and then applies these functions to some test cases. The functions `union` and `intersection` are to be applied to "sets," each set being represented by a list of atomic symbols. The functions are defined as follows. Note that they are all recursive, and both union and intersection make use of member.
|
||||
|
||||
```
|
||||
member[a;x] = [null[x]-~;e~[a;car[x]]-T;T-
|
||||
member [a;cdr [x]]]
|
||||
union[^;^] = [null[x]-.y;member[car[x];y]-union
|
||||
[cdr [x];~]; T-cons [c ar [x];union[c dr [x];~]]]
|
||||
member[a; x] = [null[x] -> F; eq[a; car[x]] -> T;
|
||||
T -> member[a; cdr[x]]]
|
||||
|
||||
union[x; y] = [null[x] -> y;
|
||||
member[car[x];y] -> union[cdr[x]; y];
|
||||
T -> cons[car[x]; union[cdr[x]; y]]]
|
||||
|
||||
intersection[x;y] = [null[x] -> NIL;
|
||||
member[car[x]; y] -> cons[car[x]; intersection[cdr[x]; y]];
|
||||
T -> intersection[cdr[x]; y]]
|
||||
```
|
||||
|
||||
To define these functions, we use the pseudo-function define. The program looks like
|
||||
|
@ -2712,47 +2736,45 @@ cator is found, and NIL otherwise.
|
|||
This pseudo-function is used to create a constant by putting the indicator APVAL
|
||||
and a value on the property list of an atomic symbol. The first argument should be an
|
||||
atomic symbol; the second argument is the value is cons[val;N1~].
|
||||
```
|
||||
|
||||
csetq[ob;val] - FEXPR pseudo-function
|
||||
#### csetq[ob; val] : FEXPR pseudo-function
|
||||
|
||||
csetq is like cset - except that it quotes its first argument instead of evaluating it.
|
||||
|
||||
#### remprop[x; ind] : SUBR pseudo-function
|
||||
|
||||
* csetq is like cset - except that it quotes its first argument instead of evaluating it.
|
||||
rempr op[x; ind] : SUBR pseudo-function f
|
||||
The pseudo-function remprop searches the list, x, looking for all occurrences of the
|
||||
indicator ind. When such an indicator is found, its name and the succeeding property
|
||||
are removed from the list. The two "endsn of the list are tied together as indicated by
|
||||
the dashed line below.
|
||||
|
||||
```
|
||||
The value of remprop is NIL.
|
||||
|
||||
When an indicator appears on a property list without a property following it, then
|
||||
it is called a flag. An example of a flag is the indicator TRACE which informs the inter-
|
||||
preter that the function on whose property list it appears is to be traced. There are two
|
||||
pseudo-functions for creating and removing flags respectively.
|
||||
```
|
||||
|
||||
- flag [I; ind] EXPR pseudo-function
|
||||
#### flag [I; ind] : EXPR pseudo-function
|
||||
|
||||
```
|
||||
The pseudo-function flag puts the flag ind on the property list of every atomic symbol
|
||||
in the list 1. Note that d cannot be an atomic symbol, and must be a list of atomic sym-
|
||||
bols. The flag is always placed immediately following the first word of the property
|
||||
list, and the rest of the property list then follows. The value of flag is NIL. No property
|
||||
list ever receives a duplicated flag.
|
||||
remflag[l; ind] : EXPR pseudo-function
|
||||
|
||||
#### remflag[l; ind] : EXPR pseudo-function
|
||||
|
||||
remflag removes all occurrences of the indicator ind from the property list of each
|
||||
atomic symbol in the list 8. It does this by patching around the indicator with a rplacd
|
||||
in a manner similar to the way remprop works.
|
||||
```
|
||||
|
||||
```
|
||||
Table Buildinrr and Table Reference Functions
|
||||
```
|
||||
### Table Building and Table Reference Functions
|
||||
|
||||
#### pair [x; y] : SUBR
|
||||
|
||||
The function pair has as value the list of pairs of corresponding elements of the lists x and y. The arguments x and y must be lists of the same number of elements. They should & be atomic symbols. The value is a dotted pair list, i. e. ((a (a p2)...
|
||||
|
||||
- pair [x; y] SUBR
|
||||
The function pair has as value the list of pairs of corresponding elements of the lists
|
||||
x and y. The arguments x and y must be lists of the same number of elements. They
|
||||
should & be atomic symbols. The value is a dotted pair list, i. e. ((a (a p2)...
|
||||
pair[x;y] = [prog[u;v; m]
|
||||
u:= x;
|
||||
v:= y;
|
||||
|
@ -2765,7 +2787,10 @@ m:= cons[cons[car[u];car[v]];m];
|
|||
u:= cdr[u];
|
||||
v:= cdr[v];
|
||||
go[~Il
|
||||
sassoc[x;y;u] SUBR functional
|
||||
```
|
||||
|
||||
#### sassoc[x; y; u] : SUBR functional
|
||||
|
||||
The function sassoc searches y, which is a list of dotted pairs, for a pair whose first
|
||||
element that is x. If such a pair is found, the value of sassoc is this pair. Otherwise
|
||||
the function u of no arguments is taken as the value of sassoc.
|
||||
|
@ -2781,12 +2806,12 @@ the S-expression y in the S-expression z.
|
|||
|
||||
T .- cons[subst[x;y;car [z]];subst [x;y;cdr[e]]]]
|
||||
|
||||
* sublis [x ; y] SUBR
|
||||
#### sublis [x ; y] : SUBR
|
||||
|
||||
Here x is a list of pairs,
|
||||
((ul vl) (u2 v2) (un vn))
|
||||
The value of sublis[x;y] is the result of substituting each v for the corresponding
|
||||
u in y.
|
||||
((u<sub>1</sub> . v<sub>1</sub>) (u<sub>2</sub> . v<sub>2</sub>) (u<sub>n</sub> . v<sub>n</sub>))
|
||||
The value of `sublis[x; y]` is the result of substituting each `v` for the corresponding
|
||||
`u` in `y`.
|
||||
Note that the following M-expression is different from that given in Section I, though
|
||||
the result is the same.
|
||||
|
||||
|
@ -2819,38 +2844,33 @@ nconc does not copy its first argument.
|
|||
* conc concatenates its arguments without copying them. Thus it changes existing list
|
||||
structure and is a pseudo-function. The value of conc is the resulting concatenated list.
|
||||
|
||||
nc - onc [x;y] SUBR pseudo-function
|
||||
#### nconc [x; y] : SUBR pseudo-function
|
||||
|
||||
```
|
||||
The function nconc concatenates its arguments without copying the first one. The
|
||||
The function `nconc` concatenates its arguments without copying the first one. The
|
||||
operation is identical to that of attrib except that the value is the entire result, (i. e. the
|
||||
modified first argument, x).
|
||||
|
||||
The program for nconc[x;y] has the program variable m and is as follows:
|
||||
```
|
||||
nconc [x; y ] = prog [[m];
|
||||
[null[x] - return[~]]
|
||||
```
|
||||
|
||||
##### [null[x] - ret~rn[~]]
|
||||
#### COPY [X] : SUBR
|
||||
|
||||
* COPY [XI SUBR
|
||||
|
||||
```
|
||||
This function makes a copy of the list x. The value of copy is the location of the
|
||||
copied list.
|
||||
```
|
||||
|
||||
##### copy[x] = [null[x] - ~~~;atom[x] - x;T -- cons[copy[car[x]]
|
||||
copy[x] = [null[x] - ~~~;atom[x] - x;T -- cons[copy[car[x]]
|
||||
|
||||
```
|
||||
co~[cdr[xllIl
|
||||
```
|
||||
|
||||
```
|
||||
reverseit] SUBR
|
||||
```
|
||||
#### reverse[t] : SUBR
|
||||
|
||||
```
|
||||
This is a function to reverse the top level of a list. Thus
|
||||
reverse[(^ B (C. D))] = ((C D) B A))
|
||||
reverse[(A B (C. D))] = ((C D) B A))
|
||||
reverse[t] = prog[[v];
|
||||
u: =t;
|
||||
```
|
||||
|
|
|
@ -147,4 +147,11 @@
|
|||
((ATOM Z) Z)
|
||||
((QUOTE T) (CONS (SUBST X Y (CAR Z)) (SUBST X Y (CDR Z))))))
|
||||
(SYSIN)
|
||||
(SYSOUT) (TERPRI) (TIMES) (TRACE) (UNTRACE) (ZEROP LAMBDA (N) (EQ N 0)))
|
||||
(SYSOUT) (TERPRI) (TIMES) (TRACE)
|
||||
(UNION LAMBDA (X Y)
|
||||
(COND
|
||||
((NULL X) Y)
|
||||
((MEMBER (CAR X) Y) (UNION (CDR X) Y))
|
||||
(T (CONS (CAR X) (UNION (CDR X) Y)))))
|
||||
(UNTRACE)
|
||||
(ZEROP LAMBDA (N) (EQ N 0)))
|
||||
|
|
|
@ -164,17 +164,32 @@
|
|||
(number? value)
|
||||
(symbol? value)
|
||||
(= value NIL))
|
||||
(do
|
||||
(try
|
||||
(.rplaca cell value)
|
||||
cell)
|
||||
cell
|
||||
(catch Throwable any
|
||||
(throw (ex-info
|
||||
(str (.getMessage any) " in RPLACA: `")
|
||||
{:cause :upstream-error
|
||||
:phase :host
|
||||
:function :rplaca
|
||||
:args (list cell value)
|
||||
:type :beowulf}
|
||||
any))))
|
||||
(throw (ex-info
|
||||
(str "Invalid value in RPLACA: `" value "` (" (type value) ")")
|
||||
{:cause :bad-value
|
||||
:detail :rplaca})))
|
||||
:phase :host
|
||||
:function :rplaca
|
||||
:args (list cell value)
|
||||
:type :beowulf})))
|
||||
(throw (ex-info
|
||||
(str "Invalid cell in RPLACA: `" cell "` (" (type cell) ")")
|
||||
{:cause :bad-value
|
||||
:detail :rplaca}))))
|
||||
{:cause :bad-cell
|
||||
:phase :host
|
||||
:function :rplaca
|
||||
:args (list cell value)
|
||||
:type :beowulf}))))
|
||||
|
||||
(defn RPLACD
|
||||
"Replace the CDR pointer of this `cell` with this `value`. Dangerous, should
|
||||
|
@ -189,17 +204,32 @@
|
|||
(number? value)
|
||||
(symbol? value)
|
||||
(= value NIL))
|
||||
(do
|
||||
(try
|
||||
(.rplacd cell value)
|
||||
cell)
|
||||
cell
|
||||
(catch Throwable any
|
||||
(throw (ex-info
|
||||
(str (.getMessage any) " in RPLACD: `")
|
||||
{:cause :upstream-error
|
||||
:phase :host
|
||||
:function :rplacd
|
||||
:args (list cell value)
|
||||
:type :beowulf}
|
||||
any))))
|
||||
(throw (ex-info
|
||||
(str "Invalid value in RPLACD: `" value "` (" (type value) ")")
|
||||
{:cause :bad-value
|
||||
:detail :rplaca})))
|
||||
:phase :host
|
||||
:function :rplacd
|
||||
:args (list cell value)
|
||||
:type :beowulf})))
|
||||
(throw (ex-info
|
||||
(str "Invalid cell in RPLACD: `" cell "` (" (type cell) ")")
|
||||
{:cause :bad-value
|
||||
:detail :rplaca}))));; PLUS
|
||||
{:cause :bad-cell
|
||||
:phase :host
|
||||
:detail :rplacd
|
||||
:args (list cell value)
|
||||
:type :beowulf}))));; PLUS
|
||||
|
||||
(defn LIST
|
||||
[& args]
|
||||
|
@ -394,38 +424,54 @@
|
|||
(make-beowulf-list (map CAR @oblist))
|
||||
NIL))
|
||||
|
||||
(defn PUT
|
||||
"Put this `value` as the value of the property indicated by this `indicator`
|
||||
of this `symbol`. Return `value` on success.
|
||||
|
||||
NOTE THAT there is no `PUT` defined in the manual, but it would have been
|
||||
easy to have defined it so I don't think this fully counts as an extension."
|
||||
[symbol indicator value]
|
||||
(let [magic-marker (Integer/parseInt "777778" 8)]
|
||||
(if-let [binding (ASSOC symbol @oblist)]
|
||||
(if-let [prop (ASSOC indicator (CDDR binding))]
|
||||
(RPLACD prop value)
|
||||
(RPLACD binding
|
||||
(make-cons-cell
|
||||
magic-marker
|
||||
(make-cons-cell
|
||||
indicator
|
||||
(make-cons-cell value (CDDR binding))))))
|
||||
(swap!
|
||||
oblist
|
||||
(fn [ob s p v]
|
||||
(make-cons-cell
|
||||
(make-beowulf-list (list s magic-marker p v))
|
||||
ob))
|
||||
symbol indicator value))))
|
||||
|
||||
(defn DEFLIST
|
||||
"For each pair in this association list `a-list`, set the property with this
|
||||
`indicator` of the symbol which is the first element of the pair to the
|
||||
value which is the second element of the pair."
|
||||
[a-list indicator]
|
||||
(map
|
||||
#(PUT (CAR %) indicator (CDR %))
|
||||
a-list))
|
||||
|
||||
(defn DEFINE
|
||||
"Bootstrap-only version of `DEFINE` which, post boostrap, can be overwritten
|
||||
in LISP.
|
||||
|
||||
The single argument to `DEFINE` should be an assoc list which should be
|
||||
nconc'ed onto the front of the oblist. Broadly,
|
||||
(SETQ OBLIST (NCONC ARG1 OBLIST))"
|
||||
[args]
|
||||
(swap!
|
||||
oblist
|
||||
(fn [ob arg1]
|
||||
(loop [cursor arg1 a arg1]
|
||||
(if (= (CDR cursor) NIL)
|
||||
(do
|
||||
(.rplacd cursor @oblist)
|
||||
(pretty-print a)
|
||||
a)
|
||||
(recur (CDR cursor) a))))
|
||||
(CAR args)))
|
||||
The single argument to `DEFINE` should be an association list of symbols to
|
||||
lambda functions"
|
||||
[a-list]
|
||||
(DEFLIST a-list 'EXPR))
|
||||
|
||||
(defn SET
|
||||
"Implementation of SET in Clojure. Add to the `oblist` a binding of the
|
||||
value of `var` to the value of `val`. NOTE WELL: this is not SETQ!"
|
||||
[symbol val]
|
||||
(when
|
||||
(swap!
|
||||
oblist
|
||||
(fn [ob s v] (if-let [binding (ASSOC symbol ob)]
|
||||
(RPLACD binding v)
|
||||
(make-cons-cell (make-cons-cell s v) ob)))
|
||||
symbol val)
|
||||
val))
|
||||
(PUT symbol 'APVAL val))
|
||||
|
||||
;;;; TRACE and friends ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
|
|
@ -64,7 +64,8 @@
|
|||
cond := lsqb (opt-space cond-clause semi-colon opt-space)* cond-clause rsqb;
|
||||
cond-clause := mexpr opt-space arrow opt-space mexpr opt-space;
|
||||
arrow := '->';
|
||||
args := mexpr | (opt-space mexpr semi-colon opt-space)* opt-space mexpr opt-space;
|
||||
args := arg | (opt-space arg semi-colon opt-space)* opt-space arg opt-space;
|
||||
arg := mexpr | sexpr;
|
||||
fn-name := mvar;
|
||||
mvar := #'[a-z][a-z0-9]*';
|
||||
mconst := #'[A-Z][A-Z0-9]*';
|
||||
|
|
Loading…
Reference in a new issue