file: LISP, node: Top, up: (DIR), next: Sources, This file is a fast edit of the MACLISP Reference Manual Dated March 6, 1976, so expect stuff to be out of date and to refer to non-existent page numbers. See other notes under Sources. Please feel free to ^R this file * MENU: * Sources:: Where this info came from Where other info is * Language:: 1. General Information 2. Data Objects 3. The Basic Actions of Lisp * Function Descriptions:: 1. Predicates 2. The Evaluator 3. Manipulating List Structure 4. Flow of Control 5. Atomic Symbols 6. Numbers 7. Character Manipulation 8. Arrays 9. Mapping Functions * Indices:: Function Index Atom Index Concept Index * System:(LISPA) 1. The Top Level 2. Break Points 3. Control Characters 4. Exceptional Condition Handling 5. Debugging 6. Storage Management 7. Miscellaneous Functions * Compiler:(LISPC) 1. Peculiarities of the Compiler 2. Declarations 3. Running Compiled Functions 4. Running the Compiler 5. The Lisp Assembly Program 6. Internal Implementation Details 7. Calling Programs Written in Other Languages * Input and Output:(LISPIO) 1. The Reader 2. The Printer 3. Files 4. Terminals 5. Requests to the Host Operating System 6. "Old I/O" 7. "Moby I/O" Using Maclisp:: NO INFORMATION 1. Getting Used to Lisp 2. Extending the Language 3. The Grinder 4. Editors 5. Implementing Subsystems with Maclisp 6. Internal Implementation Details 7. Maclisp Glossary 8. Comparison with LISP 1.5 9. Comparison with InterLISP  file: LISP, node: Sources, previous: Top, up: Top, next: Language, The sources on LISP are spread out on ITS. The bulk of this file comes from a small portion of the 1976 MACLISP Reference Manual. Other information sources are (check on MC: for current versions): .info.; lisp cursor 7/26/77 talks about (cursorpos ...) lisp news continually update list of changes lisp sfa 11/24/78 about software file arrays lspord > 3/4/77 ? (1979: no such file) manual update 3/4/78 newio stuff 1/27/79 X lspman; manual ascii 3/6/76 33% of the MACLISP Ref Manual intel > how to convert Interlisp -> MACLISP new stuff 4/14/75 ? X ch12 > 8/3/78 toplevel stuff X ch13 > 1/6/75 basic I/O ch14 > 7/21/77 compilation libdoc; a users library full of goodies liblsp; tvlisp; users library of TV hacks and your local LISP GURU ^--- an "X" in this column mean the file has been incorporated into this file  file: LISP, node: Language, previous: Sources, up: Top, next: General Information, Source: MACLISP Manual 3/6/76 * MENU: * General Information:: 1.1 The Maclisp Language . . . 1.2 Structure of the Manual . 1.3 Notational Conventions . . * Data Objects:: * The Basic Actions of Lisp:: 3.1 Binding of Variables . . . 3.2 Evaluation of Forms . . . 3.3 Application of Functions . 3.4 Special Forms . . . . . . 3.5 Binding Context Pointers .  file: LISP, node: General Information, previous: Language, up: Language, next: Data Objects, Source: MACLISP Manual 3/6/76 1. General Information 1.1 The Maclisp Language . . . 1.2 Structure of the Manual . 1.3 Notational Conventions . . 1.1 The Maclisp Language Maclisp is a dialect of Lisp developed at M.I.T.'s Project MAC and M.I.T.'s Artificial Intelligence Laboratory for use in artificial intelligence research and related fields. Maclisp is descended from the commonly-known Lisp 1.5 dialect; however, many features of the language have been changed or augmented. This document is intended both as a reference source for the language and as a user's guide to three implementations. These are, in chronological order, the M.I.T. Artificial Intelligence Lab's implementation on the DEC pdp-10 computer under their operating system ITS, hereafter referred to as "the ITS implementation," Project MAC's implementation on Honeywell's version of the Multics system, hereafter referred to as "the Multics implementation," and the version that runs on the DEC pdp-10 under DEC's TOPS-10 operating system, hereafter called "the DEC-10 implementation." The DEC-10 implementation also runs under TENEX by means of a TOPS-10 emulator. Since the ITS and DEC-10 implementations are closely related, they are sometimes referred to collectively as the pdp-10 implementation. There are reputed to be several other implementations. These implementations are mostly compatible; however, some implementations have extra features designed to exploit peculiar features of the system on which they run, and some implementations are temporarily missing some features. Most programs will work on any implementation, although it is possible to write machine-dependent code if you try hard enough. The Maclisp system is structured as an environment, which is essentially a set of names and bindings of those names to data structures and function definitions. The environment contains a large number of useful functions. These functions can be used through an interpreter to define other functions, to control the environment, to do useful work, etc. The interpreter is the basic user interface to the system. This is how the user enters "commands." When Maclisp is not doing anything else, such as running a program, it waits for the user to enter a Lisp form. This form is evaluated and the value is printed out. The form may call upon one of the system functions (or a user-defined function, of course) to perform some useful task. The evaluation of a form may initiate the execution of a large and complex program, perhaps never returning to the "top level" interpreter, or it may perform some simple action and immediately wait for the user to type another form. It is also possible to get into the interpreter while a program is running, using the break facility. This is primarily used in debugging and related programming activities. The functions invoked by the top-level interpreter may be executable machine programs, or they may themselves be interpreted. This is entirely a matter of choice and convenience. The system functions are mostly machine programs. User functions are usually first used interpretively. After they work, the compiler may be applied to them, turning them into machine programs which can then be loaded into the environment. All of this is done within a single consistent language, Lisp, whose virtue is that the data structure is simple and general enough that programs may easily operate on programs, and that the program structure is simple and general enough that it can be used as a command language. .bp 1.2 Structure of the Manual Source: MACLISP Manual 3/6/76 The manual is generally structured into sections on particular topics; each section contains explanatory text and function definitions, interspersed. In general, each section contains both elementary and complex material, with complexity increasing toward the end of the section. An axiomatic, step-by-step development is not used. Frequently the more complex information in a section will assume knowledge from other sections which appear later in the manual. The new user is advised to skip around, reading early chapters and early sections of chapters first. Often descriptions of Lisp functions will be given not only in prose but also in terms of other Lisp functions. These are as accurate as possible, but should not be taken too literally. Their main purpose is to serve as a source of examples. Accessing information in the manual is dependent on both the user's level of ability and the purpose for which she or he is using the manual. Though cover to cover reading is not recommended (though not excluded), it is suggested that someone who has never previously seen this manual browse through it, touching the beginning of each subdivision that is listed in the Table of Contents, in order to familiarize himself or herself with the material that it contains. To find an answer to some particular question, one must use one of the provided access methods. Since the manual is structured by topics one can use the Table of Contents that is found at the beginning of the manual, and the more detailed tables of contents found at the beginning of each of the six major parts, to find where information of a general class will be found. Entry into the manual is also facilitated by the Glossary and the Concept Index, which are found at the end. Also at the end of the manual are a Function Index and an Atomic Symbol Index which are probably most useful to a regular and repeated user of the dialect, or to an experienced user of another dialect, who wishes to find out the answer to a question about a specific function. When one section of the manual assumes knowledge of another section a page number reference to the other section will generally be given. .bp 1.3 Notational Conventions Source: MACLISP Manual 3/6/76 There are some conventions of notation that must be mentioned at this time, due to their being used in examples. Most numbers are in octal radix (base eight). Numbers with a decimal point and spelled-out numbers are in decimal radix. It is important to remember that by default Maclisp inputs and outputs all numbers in octal radix. If you want to change this, see the variables base and ibase. A combination of the characters equal sign and greater than symbol, "=>", will be used in examples of Lisp code to mean evaluation. For instance, "F => V" means that evaluating the form F produces the value V. All uses of the phrase "Lisp reader," unless further qualified, refer to that part of the Lisp system which reads input, and not to the person reading this document. The terms "S-expression" and "Lisp object" are synonyms for "any piece of Lisp data." The character "$" always stands for dollar-sign, never for "alt mode," unless that is specifically stated. The two characters accent acute, "'", and semi-colon, ";", are examples of what are called macro characters. Though the macro character facility, which is explained in Part 5, is not of immediate interest to a new user of the dialect, these two macro characters come preset by the Lisp system and are useful. When the Lisp reader encounters an accent acute, or quote mark, it reads in the next S-expression and encloses it in a quote-form, which prevents evaluation of the S-expression. That is: 'some-atom turns into: (quote some-atom) and '(cons 'a 'b) turns into (quote (cons (quote a) (quote b))) The semi-colon (;) is used as a commenting character. When the Lisp reader encounters it, the remainder of the line is discarded. The term "newline" is used to refer to that character or sequence of characters which indicates the end of a line. This is implementation dependent. In Multics Maclisp, newline is the Multics newline character, octal 012. In ITS Maclisp, newline is carriage return (octal 015), optionally followed by line feed (octal 012.) In dec-10 Maclisp, newline is carriage return followed by line feed. All Lisp examples in this manual are written according to the case conventions of the Multics implementation, which uses both upper and lower case letters and spells the names of most system functions in lower case. Some implementations of Maclisp use only upper case letters because they exist on systems which are not, or have not always been, equipped with terminals capable of generating and displaying the full ascii character set. However, these implementations will accept input in lower case and translate it to upper case, unless the user has explicitly said not to.  file: LISP, node: Data Objects, previous: General Information, up: Language, next: The Basic Actions of Lisp, Source: MACLISP Manual 3/6/76 Lisp works with pieces of data called "objects" or "S-expressions." These can be simple "atomic" objects or complex objects compounded out of other objects. Functions, the basic units of a Lisp program, are also objects and may be manipulated as data. Objects come in several types. All types are manifest; that is, it is possible for a program to tell what type an object is just by looking at the object itself, so it is not necessary to declare the types of variables as in some other languages. One can make declarations, however, in order to aid the compiler in producing optimal code. (See part 4.2.) It is important to know that Lisp represents objects as pointers, so that a storage cell (a "variable") will hold any object, and the same object may be held by several different storage cells. For example, the same identical object may be a component of two different compound objects. The data-types are divided into three broad classes: the atomic types, the non-atomic types, and the composite types. Objects are divided into the same three classes according to their type. Atomic objects are basic units which cannot be broken down by ordinary chemical means (car and cdr), while non-atomic objects are structures constructed out of other objects. Composite objects are indivisible, atomic, entities which have other objects associated with them. These other objects may be examined and replaced. The atomic data types are numbers, atomic symbols, strings, and subr-objects. Atomic symbols can also be regarded as composite. See below. In Lisp numbers can be represented by three types of atomic objects: fixnums, flonums, and bignums. A fixnum is a fixed-point binary integer whose range of values is machine-dependent. A flonum is a floating-point number whose precision and range of values are machine-dependent. A bignum is an infinite- precision integer. It is impossible to get "overflow" in bignum arithmetic, as any integer can be represented by a bignum. However, fixnum and flonum arithmetic is faster than bignum arithmetic and requires less memory. Sometimes the word "fixnum" is used to include both fixnums and bignums (i.e. all integers); in this manual, however, the word "fixnum" will never be used to include bignums unless that is explicitly stated. The printed representations for numbers are as follows: a fixnum is represented as a sequence of digits in a specified base, usually octal. A trailing decimal point indicates a decimal base. A flonum is represented as a set of digits containing an embedded or leading decimal point and/or a trailing exponent. The exponent is introduced by an upper or lower case "e". A bignum looks like a fixnum except that it has enough digits that it will not fit within the range available to fixnums. Any number may be preceded by a + or - sign. Some examples of fixnums are 4, -1232, -191., +46. An example of a bignum is 1565656565656565656565656565656565. Some examples of flonums are: 4.0, .01, -6e5, 4.2e-1. One of the most important Lisp data types is the atomic symbol. In fact, the word "atom" is often used to mean just atomic symbols, and not the other atomic types. An atomic symbol has associated with it a name, a value, and possibly a list of "properties". The name is a sequence of characters, which is the printed representation of the atomic symbol. This name is often called the "pname," or "print-name." A pname may contain any ascii character except the null character, which causes trouble in some implementations. For example, a certain atomic symbol would be represented externally as foo; internally as a structure containing the value, the pname "foo", and the properties. There are two special atomic symbols, t and nil. These always have their respective selves as values and their values may not be changed. nil is used as a "marker" in many contexts; it is essential to the construction of data structures such as lists. t is usually used when an antithesis to nil is required for some purpose, e.g. to represent the logical conditions "true" and "false." Another property of the special atomic symbol nil is that its car and its cdr are always nil. The value of an atomic symbol can be any object of any type. There are functions to set and get the value of a symbol. Because atomic symbols have values associated with them, they can be used as variables in programs and as "dummy arguments" in functions. It is also possible for an atomic symbol to have no value, in which case it is said to be "undefined" or "unbound." The property list of an atomic symbol is explained on page 2-48. It is used for such things as recording the fact that an atomic symbol is the name of a function. An atomic symbol with one or no characters in its pname is often called a "character object" and used to represent an ascii character. The atomic symbol with a zero-length pname represents the ascii null character, and the symbols with one-character pnames represent the character which is their pname. Functions which take character objects as input usually also accept a string one character long or a fixnum equal to the ascii-code value for the character. Character objects are always interned on the obarray (see page 2-54). Another Lisp data type is the string. This is a sequence of characters (possibly zero-length). Strings are used to hold messages to be typed out and to manipulate text when the structure of the text is not appropriate for the use of "list processing." The printed representation of a string is a sequence of characters enclosed in double-quotes, e.g. "foo". If a " is to be included in the string, it is written twice, e.g. "foo""bar" is foo"bar. In implementations without strings, atomic symbols are used instead. The pdp-10 implementations currently lack strings. A "subr-object" is a special atomic data-type whose use is normally hidden in the implementation. A subr-object represents executable machine code. The functions built into the Lisp system are subr-objects, as are user functions that have been compiled. A subr-object has no printed representation, so each system function has an atomic symbol which serves as its name. The symbol has the subr-object as a property. One composite data type is the array. An array consists of a number of cells, each of which may contain any Lisp object. The cells of an array are accessed by subscripting; each cell is named by a tuple of integers. An array may have one or more dimensions; the upper limit on the number of dimensions is implementation-defined. An array is not always associated with an atomic symbol which is its name. Rather, an array is always designated by an array-pointer, which is a special kind of atomic Lisp object. Frequently, an array-pointer will be placed on the property list of a symbol under the indicator array and then that symbol will be used as the name of the array, since symbols can have mnemonic names and a reasonable printed representation. See page 2-85 for an explanation of how to create, use, and delete arrays. Another composite data type is the file-object, which is described on part 5.3. The sole non-atomic data type is the "cons." A cons is a structure containing two components, called the "car" and the "cdr" for historical reasons. (These are names of fields in an IBM 7094 machine word.) These two components may be any Lisp object, even another cons (in fact, they could even be the same cons). In this way complex structures can be built up out of simple conses. Internally a cons is represented in a form similar to: _____________________________________ | | | | car | cdr | _|__________________|__________________| where the boxes represent cells of memory large enough to hold a pointer, and "car" and "cdr" are two pointers to objects. The printed representation of a cons is the "dotted-pair" notation (A . B) where A is the car and B is the cdr. Another way to write the internal representation of a cons, which is more convenient for large structures, is: ---> o -----> cdr | | V car There are three Lisp functions associated with conses: cons, car, and cdr. The function cons combines its two arguments into a cons; (1 . 2) can be generated by evaluating (cons 1 2). The function car returns the car component of its argument, and the function cdr returns the cdr component of its argument. One type of structure, built out of conses, that is used quite often, is the "list." A list is a row of objects, of arbitrary length. A list of three things 1, 2, and 3 is constructed by (cons 1 (cons 2 (cons 3 nil))); nil is a special atom that is used to mark the end of a list. The structure of a list can be diagrammed as: ---> o ----> o ----> o ----> nil | | | | | | V V V 1 2 3 From this it can be seen that the car of a list is its first element, that the cdr of a list is a list of the elements after the first, and that the list of no elements is the same as nil. This list of 1, 2, and 3 could be represented in the dot-notation used for conses as (1 . (2 . (3 . nil))). However, a more convenient notation for the printed representation of lists has been defined: the "list-notation" (1 2 3). It is also possible to have a hybrid of the two notations which is used for structures which are almost a list except that they end in an atom other than nil. For example, (A . (B . (C . D))) can be represented as (A B C . D). A list not containing any elements is perfectly legal and frequently used. This zero-length list is identified with the atom nil. It may be typed in as either nil or ().  file: LISP, node: The Basic Actions of Lisp, previous: Data Objects, up: Language, next: Binding of Variables, Source: MACLISP Manual 3/6/76 * MENU: * Binding of Variables:: * Evaluation of Forms:: * Application of Functions:: * Special Forms:: * Binding Context Pointers::  file: LISP, node: Binding of Variables, previous: The Basic Actions of Lisp, up: The Basic Actions of Lisp, next: Application of Functions, Source: MACLISP Manual 3/6/76 The basic primitives of programming in Lisp are variables, forms, and functions. A variable is an atomic symbol which has a value associated with it; the symbol is said to be bound to that value. The value may of course be any Lisp object whatsoever. The atomic symbol acts simply as a name by which the program may refer to the value while it is processing it. This is similar to the concept of variables in other programming languages. However, Lisp's concept of the scope of names is subtly different from that of most "block-structured" languages. At a given moment, a variable may actually have several bindings in existence. Only the most recent, or current binding, can be used. When a new binding is created, the previous one is pushed onto a stack. It will become accessible again when the binding which superseded it is removed. Creation and removal of bindings is synchronized with subroutine calling (and with certain special forms described below) so this mechanism corresponds closely to the "local variables" concept of other programming languages. However, Lisp considers that there is only one variable whose binding changes, rather than several separate variables which happen to have the same name. Any reference to a variable, even from outside the particular program which gave it its current binding, gets the current binding and not one determined by "scope rules." It is possible to simulate the other concept of scope of names by using binding context pointers, which are described later (see page 1-22). Unlike many other languages, Lisp does not combine the concepts of name and storage. Many languages associate with a variable (a name) a piece of storage which can hold one object of a particular type, such as a floating point number. The variable's value resides in this storage. It is then impossible for two variables to really have "the same" value; one could have a copy of the value of another but not the same identical object. The situation in Lisp is quite different. Binding a variable to a value is not copying the value into storage associated with that variable. Values exist as separate objects in their own right and in their own storage. Binding is simply an association between a variable and a value; consequently there is no reason why two variables cannot have truly identical values. Similarly, erasing the binding between a variable and its value does not destroy or throw away the value; it simply breaks the association. Of course, if there is no other use for the value the storage it occupies will eventually be reclaimed by the system and put to more productive use. Often these processes of creating a new binding of a variable to a value and reverting to a previous binding are referred to as binding and unbinding the variable, respectively. A slightly different way of creating a binding between a variable and a value is assignment. When a variable is bound to a value, the previous binding is saved and can be restored, but when a variable has a value assigned to it, the previous binding is not saved, but is simply replaced. Thus binding may be regarded as creating a new level of usage of a variable, while assignment switches a variable to a different value within the same level. For instance, a subroutine or function may bind a variable to an initial value when it is entered, and then proceed to make use of that variable, possibly assigning a different value to it from time to time. The initial binding of the variable establishes the (temporary) ownership of that variable by the subroutine. Due to the subtlety of the distinction between binding and assignment, some people have proposed that assignment be eliminated wherever possible. The Maclisp do function can often be useful in this regard. There are several program constructs by which a variable can be bound. These will be explained after forms and functions have been introduced. 3.2 Evaluation of Forms The process of "executing" a Lisp program consists of the evaluation of forms. Evaluation takes a form and produces from it a value (any Lisp object), according to a strict set of rules which might be regarded as the complete semantics of Lisp. If the form is atomic, it is evaluated in a way which depends on its data type. An atomic symbol is a variable; it evaluates to the value to which it is currently bound. If it is not bound, an error occurs. (See part 3.4.) A number or a string is a literal constant; it evaluates to itself. The special atomic symbols t and nil are also treated as constants. A constant can also be created by use of the quote special form; the value of (quote x) is x. If the form is a list, its first element specifies the operation to be performed, and its remaining elements specify arguments to that operation. Non- atomic forms come in two types: special forms, which include the necessary programming operations such as assignment and conditionals, and function references, in which the "operation" is a function which is applied to the specified arguments. Thus functional composition is the method by which programs are built up out of parts - as distinguished from composition of data structures, for example. Lisp functions correspond closely to subroutines in other programming languages. A function may be either a primitive which is directly executable by the machine, called a subr (short for "subroutine"), or a function defined by composition of functions and special forms, called an expr (short for "expression.") Most subrs are built in to the language, but it is possible for a user to convert his exprs into subrs by using the compiler (see part 4.) This gains speed and compactness at some cost in debugging features. There is additional complexity because special forms are actually implemented as if they were function references. There is a special type of subr called an fsubr which is used for this purpose. An fsubr is permitted to make any arbitrary interpretation of its argument specification list, instead of following the standard procedure which is described below. It is also possible to define a special form by an expr, which is then called a fexpr. Most of the built-in special forms are handled specially by the compiler. They are compiled as the appropriate code rather than as a call to the fsubr. Other types of functions are lsubr, which is just a subr with a variable number of arguments, lexpr, which is an expr with a variable number of arguments, and macro, which is a type of special form whose result is not a value, but another form; this allows a "transformational" type of semantics. Consider the form (F A1 A2 ... An) The evaluator first examines F to see if it is a function which defines a special form, i.e. an fsubr, a fexpr, or a macro. If so, F is consulted and it decides how to produce a value. If not, F must be an ordinary function. The sub-forms A1 through An are evaluated, producing n arguments, and then the definition of F is applied to the arguments. (Application is described in the following section.) This yields a result (some Lisp object), which is then taken as the value of the form. An atomic form of some random type, such as a subr-object, a file, or an array-pointer, evaluates to something random, often itself; or else causes an error depending on the convenience of the implementation. Note that an array- pointer is different from an atomic symbol which happens to be the name of an array; such an atomic symbol is evaluated the same as any other atomic symbol.  file: LISP, node: Application of Functions, previous: Binding of Variables, up: The Basic Actions of Lisp, next: Special Forms, Source: MACLISP Manual 3/6/76 When a non-atomic form is evaluated, the function specified by that form is combined with the arguments specified by that form to produce a value. This process is called application; the function is said to be applied to the arguments. The first step in application is to convert the function-specifier into a functional expression (sometimes confusingly called a functional form.) A functional expression is a Lisp object which is stylized so that Lisp can know how to apply it to arguments. The rules for this conversion will be described after the types of functional expressions have been explained. There are basically two types of functional expression. A lambda-expression is a functional expression which specifies some variables which are to be bound to the arguments, and some forms which are to be evaluated. One would expect the forms to depend on the variables. The value of the last form is used as the value of the application of the lambda-expression. Any preceding forms are present purely for their side-effects. A lambda-expression looks like: (lambda (a b c d) form1 form2 form3) Here a, b, c, and d are the variables to be bound to the values of the arguments, called the lambda-variables. If at a certain moment the current binding of a was the one created by this lambda-expression, a would be said to be lambda-bound. Clearly this lambda-expression is a function which accepts four arguments. The application of the functional expression to four arguments produces a value by evaluating form1, then form2, and then form3. The value of form3 is the value of the whole form. For example, the value of the form ((lambda (a b) b) 3 4) is 4. The functional expression used is a very simple one which accepts two arguments and returns the second one. If we grant the existence of a primitive addition operation, whose functional expression may be designated by +, then the value of the form ((lambda (a b) (+ a b)) 3 4) is 7. Actually, (+ 3 4) evaluates to the same thing. The second basic type of functional expression is the subr, which is a program directly executable by the machine. The arguments of the form are conveyed to this program in a machine-dependent manner, it performs some arbitrary computation, and it returns a result. The built in primitives of the language are subrs, and the user may write lambda-expressions which make use of these subrs to define his own functions. The compiler may be used to convert user functions into subrs if extra efficiency is required. It is extremely convenient to be able to assign names to functional expressions. Otherwise the definition of a function would have to be written out in full each time it was used, which would be impossibly cumbersome. Lisp uses atomic symbols to name functions. The "property list" mechanism is used to associate an atomic symbol with a functional expression. (See page 2-48 for an explanation of property lists.) Because the binding mechanism is not used, it is possible for the same name to be used for both a variable and a function with no conflict. Usually the defun special form is used to establish the association between a function name and a functional expression. Thus, the car of a form may be either a functional expression itself, or an atomic symbol which names a functional expression. In the latter case, the name of the "property" which associates the symbol with the expression gives additional information: A lambda-expression is normally placed under the expr property. This defines an ordinary expr. If a lambda-expression is placed under the fexpr property, it defines a special form. In that case, the first lambda-variable is bound to the cdr of the form being evaluated. For example, if foo is a fexpr, and (foo (a b) (c d)) is evaluated, then foo's lambda-variable would be bound to ((a b) (c d)). A second lambda-variable may optionally be included in a fexpr. It will be bound to a "binding context pointer" to the context of the evaluation of the form. If a lambda-expression with one lambda-variable is placed under the macro property, it defines the "macro" special form mentioned above. The lambda- expression is applied to the entire form, as a single argument, and the value is a new form that is evaluated in place of the original form. If a subr-object is placed under the subr property, it defines a subr. If a subr-object is placed under the fsubr property, it defines a special form. A subr-object under the lsubr property defines a subr which accepts varying numbers of arguments. There are some additional refinements. A lambda-expression which accepts varying numbers of arguments, called a lexpr, looks as follows: (lambda n form1 form2) The single, unparenthesized, lambda-variable n is bound to the number of arguments. The function arg, described on page 2-10, may be used to obtain the arguments. Another property which resembles a functional property is the autoload property. If Lisp encounters an autoload property while searching the property list of a symbol for functional properties, it loads in the file of compiled functions specified by the property, then searches the property list again. Presumably the file would contain a definition for the function being applied, and that definition would be found the second time through. In this way packages of functions which are not always used can be present in the environment only when needed. An array may also be used as a function. The arguments are the subscripts and the value is the contents of the selected cell of the array. An atomic symbol with an array property appearing in the function position in a form causes that array to be used. If the function-specifier of a form doesn't meet any of the above tests, Lisp evaluates it and tries again. In this way, "functional variables" and "computed functions" can be used. However, it is better to use the funcall function. (See page 2-11.) There are some other cases of lesser importance: There is an obscure type of functional expression called a label-expression. It looks like (label name (lambda (...) ...)) The atomic symbol name is bound to the enclosed lambda-expression for the duration of the application of the label-expression. Thus if name is used as a functional variable this temporary definition will be used. This is mostly of historical interest and is rarely used in actual programming. Another type of functional expression is the funarg. A funarg is a list beginning with the atomic symbol funarg, as you might expect, and containing a function and a binding context pointer. Applying a funarg causes the contained function to be applied in the contained binding context instead of the usual context. funargs are created by the *function special form. An expr property may be an atomic symbol rather than a lambda-expression. In this case, the atomic symbol is used as the function. The original symbol is simply a synonym for it. In addition to the variety of application just described, which is used internally by the evaluation procedure, there is a similar but not identical application procedure available through the function apply. The main difference is that the function and the arguments are passed to apply separately. They are not encoded into a form, consequently macros are not accepted by this version of application. Note that what is passed to apply is a list of arguments, not a list of expressions which, evaluated, would yield arguments.  file: LISP, node: Special Forms, previous: Application of Functions, up: The Basic Actions of Lisp, next: Binding Context Pointers, Source: MACLISP Manual 3/6/76 This section briefly describes some of the special forms in Maclisp. For full details on a specific special form, consult the Function Index in the back. Constants (quote x) evaluates to the S-expression x. (function x) evaluates to the functional expression x. There is little real difference between quote and function. The latter is simply a mnemonic reminder to anyone who reads the program - including the compiler - that the specified expression is supposed to be some kind of function. Conditionals Conditionals control whether or not certain forms are evaluated, depending on the results of evaluating other forms. Thus both the value and the side effects of the conditional form can be controlled. (cond (predicate form1 form2...) (predicate form1 form2...)...) is a general conditional form. The lists of a predicate and some forms are called clauses. The cond is evaluated by considering the clauses one by one in the order they are written. The predicate of a clause is evaluated, and if the result is true, that is, anything other than nil, then the forms in that clause are evaluated and the cond is finished without examining the remaining clauses. If the result is not true, i.e. if it is nil, then the next clause is examined in the same way. If all the clauses are exhausted, that is not an error. The value of a cond is the value of the last form it evaluates, which could be nil if no predicate is true, or the value of a predicate if that predicate is true but has no forms in its clause. (and form1 form2 form3...) evaluates the forms in succession until one is nil or the forms are exhausted, and the result is the value of the last form evaluated. (or form1 form2 form3...) evaluates the forms until one is non-nil or the forms are exhausted, and the result is the value of the last form evaluated. Non-Local Exits (catch form tag) evaluates the form, but if the special form (throw value tag) is encountered, and the tags are the same, the catch immediately returns the value without further ado. See page 2-40 for the full details. Iteration (prog (variable...) form-or-tag ...) allows Fortranoid "programs" with goto's, local variables, and return's to be written. (do ...) is the special form for iteration. See page 2-34 for the details of prog and do. Defining Functions (defun name (arg1 arg2...) form1 form2...) defines an (interpreted) function. See page 2-56 for full details. Error Control (break name t) causes ";bkpt name" to be typed out and gives control to a read-eval-print loop so that the user can examine and change the state of the world. When he is satisfied, the user can cause the break to return a value. See part 3.2 for the details of break. (errset form) evaluates the form, but if an error occurs the errset simply returns nil. If no error occurs, the value is a list whose single element is what the value of the form would have been without errset. Assignment (setq var1 value1 var2 value2...) assigns the values to the variables. The values are forms which are evaluated. (store (array subscript1 subscript2...) value) assigns the value to the array cell selected by subscripting. See part 2.8 for further information on arrays. Miscellaneous Parameters (status name -optional args-) returns miscellaneous parameters of LISP. name is a mnemonic name for what is to be done. (sstatus name -optional args-) sets miscellaneous parameters. See part 3.7 for the details of status and sstatus. Pretty-Printing (grindef x) prettily prints the value and function definition (if any) of the atomic symbol x. Indentation is used to reveal structure, the quote special form is represented by ', etc. See part 6.3 for the details. Tracing (trace name) causes the function name to print a message whenever it is called and whenever it returns. See part 3.5 for the many features and options of trace.  file: LISP, node: Binding Context Pointers, previous: Special Forms, up: The Basic Actions of Lisp, next: Function Descriptions, Source: MACLISP Manual 3/6/76 There is a special type of object called a binding context pointer, or sometimes an "a-list pointer", which can be used to refer to a binding context (a set of bindings of variables and values which was extant at a particular instant.) Due to the stack implementation of Maclisp, a binding context pointer is only valid while control is nested within the binding context it names. It is not possible to exit from within a binding context but keep it around by retaining a pointer to it. A binding context pointer is either a negative fixnum or nil. nil means the "global" or "top level" binding context. The negative fixnum is a special value of implementation dependent meaning which should be obtained only from one of the four following sources: the function evalframe, the function errframe, the special form *function, or the second lambda-variable of a fexpr. The only use for binding context pointers is to pass them to the functions eval and apply to specify the binding context in which variables are to be evaluated and assignments are to be performed during that evaluation or application. Binding context pointers are also used internally by *function. When it generates a funarg, it puts in the funarg the functional expression it was given and a binding context pointer designating the binding environment current at the time *function was called.  file: LISP, node: Function Descriptions, previous: Binding Context Pointers, up: Top, next: Predicates, Source: MACLISP Manual 3/6/76 * MENU: * Predicates:: * The Evaluator:: * Manipulating List Structure:: 3.1 Conses 3.2 Lists 3.3 Alteration of List Structure 3.4 Tables 3.5 Sorting * Flow of Control:: 4.1 Conditionals 4.2 Iteration 4.3 Non-local Exits 4.4 Causing and Controlling Errors * Atomic Symbols:: 5.1 The Value Cell 5.2 The Property List 5.3 The Print-Name 5.4 Interning of Symbols 5.5 Defining Atomic Symbols as Functions * Numbers:: 6.1 Number Predicates 6.2 Comparison . . . 6.3 Conversion . . . 6.4 Arithmetic . . . 6.5 Exponentiation and Logarithm Functions 6.6 Trigonometric Functions . . . . . . . 6.7 Random Functions . . . . . . . . . . . 6.8 Logical Operations on Numbers . . . . * Character Manipulation:: 7.1 Character Objects . . . . . . . . . . * Arrays:: * Mapping Functions::  file: LISP, node: Predicates, previous: Function Descriptions, up: Function Descriptions, next: The Evaluator, Source: MACLISP Manual 3/6/76 A predicate is a function which tests for some condition involving its argument and returns t if that condition is true, or nil if it is not true. The following predicates are for checking data types. These predicates return t if their argument is of the type indicated by the name of the function, nil if it is of some other type. Note that the name of most predicates ends in the letter p, by convention. atom SUBR 1 arg The atom predicate returns nil if its argument is a dotted-pair or a list, or t if it is any kind of atomic object such as a number, a character string, or an atomic symbol. fixp SUBR 1 arg The fixp predicate returns t if its argument is a fixnum or a bignum, otherwise nil. floatp SUBR 1 arg The floatp predicate returns t if its argument is a flonum, nil if it is not. bigp SUBR 1 arg The predicate bigp returns t if its argument is a bignum, and nil otherwise. numberp SUBR 1 arg The numberp predicate returns t if its argument is any kind of number, nil typep SUBR 1 arg typep is a general function for constructing type-predicates. It returns an atomic symbol describing the type of its argument, chosen from the list (fixnum flonum bignum list symbol string array random) symbol means atomic symbol. list means a list or a cons. array means array-pointer. random is for all types that don't fit in any other category. Thus numberp could have been defined by: (defun numberp (x) (and (memq (typep x) '(fixnum flonum bignum)) t)) The following two functions only exist in the Multics implementation. stringp SUBR 1 arg The stringp predicate returns t if its argument is a string, otherwise nil. subrp SUBR 1 arg The subrp predicate returns t if its argument is a "subr" object, i.e. a pointer to the machine code for a compiled or system function. Example: (subrp (get 'car 'subr)) => t The following are a more miscellaneous set of predicates. eq SUBR 2 args (eq x y) => t if x and y are exactly the same object, nil otherwise (cf. equal). It should be noted that things that print the same are not necessarily eq to each other. In particular, numbers with the same value need not be eq, and two similar lists are usually not eq. In general, two atomic symbols with the same print-name are eq, but it is possible with maknam or multiple obarrays to generate symbols which have the same print- name but are not eq. Examples: (eq 'a 'b) => nil (eq 'a 'a) => t (eq '(a . b) '(a . b)) => nil (usually) (eq (cons 'a 'b) (cons 'a 'b)) => nil (always) (setq x '(a . b)) (eq x x) => t since it is the same copy of (a . b) in both arguments. (setq x (setq y 17)) (eq x y) => t or nil depending on the implementation. You can never rely on numbers being eq. equal SUBR 2 args The equal predicate returns t if its arguments are similar (isomorphic) objects. (cf. eq) Two numbers are equal if they have the same value (a flonum is never equal to a fixnum though). Two strings are equal if they have the same length, and the characters composing them are the same. All other atomic objects are equal if and only if they are eq. For dotted pairs and lists, equal is defined recursively as the two car's being equal and the two cdr's being equal. Thus equal could have been defined by: (defun equal (x y) (or (eq x y) (and (numberp x) (numberp y) (numequal x y)) (and (not (atom x)) (not (atom y)) (equal (car x) (car y)) (equal (cdr x) (cdr y))))) if there was an auxiliary function for numeric equality: (defun numequal (x y) (and (eq (typep x) (typep y)) (zerop (difference x y)))) This numequal function is not the same as the Maclisp numeric-equality function, =, because the latter only compares non-big numbers. As a consequence of the above definition, it can be seen that equal need not terminate when applied to looped list structure. In addition, eq always implies equal. An intuitive definition of equal (which is not quite correct) is that two objects are equal if they look the same when printed out. not SUBR 1 arg not returns t if its argument is nil, otherwise nil. null SUBR 1 arg This is the same as not. Both functions are provided for the sake of clarity. null should be used to check if something is nil and return a logical value. not should be used to invert the sense of a logical value. Even though Lisp uses nil to represent logical "false," you shouldn't make understanding your program depend on this. For example, one often writes (cond ((not (null x)) ... ) ( ... )) rather than (cond (x ... ) ( ... )) There is no loss of efficiency since these will compile into exactly the same instructions. See also the number predicates (page 2-59).  file: LISP, node: The Evaluator, previous: Predicates, up: Function Descriptions, next: Manipulating List Structure, Source: MACLISP Manual 3/6/76 eval LSUBR 1 or 2 args (eval x) evaluates x, as a form, atomic or otherwise, and returns the result. (eval x p) evaluates x in the context specified by the binding context pointer p. Example: (setq x 43 foo 'bar) (eval (list 'cons x 'foo)) => (43 . bar) apply LSUBR 2 or 3 args (apply f y) applies the function f to the list of arguments y. Unless f is an fsubr or fexpr, such as cond or and, which evaluates its arguments in a funny way, the arguments in the list y are used without being evaluated. Examples: (setq f '+) (apply f '(1 2 3)) => 6 (setq f '-) (apply f '(1 2 3)) => -4 (apply 'cons '((+ 2 3) 4)) => ((+ 2 3) . 4) not (5 . 4) (apply f y p) works like apply with two arguments except that the application is done with the variable bindings specified by the binding context pointer p. quote FSUBR The special form (quote x) returns x without trying to evaluate it. quote is used to include constants in a form. For convenience, the read function normally converts any S-expression preceded by the apostrophe or acute accent character (') into the quote special form. For example, (setq x '(some list)) is converted by the reader to: (setq x (quote (some list))) which when evaluated causes the variable x to be set to the constant list value shown. For more information on input syntax, see the detailed discussion in part 5.1. quote could have been defined by: (defun quote fexpr (x) (car x)) function FSUBR function is like quote except that its argument is a functional expression. To the interpreter, quote and function are identical, but the compiler needs to be able to distinguish between a random piece of data, which should be left alone, and a function, which should be compiled into machine code. Example: (mapcar (function (lambda (p q) (cond ((eq p '*) q) (t (list p '= q)) ))) first-list-of-things (compute-another-list) ) calls mapcar with three arguments, the first of which is the function defined by the lambda-expression. The actual value passed to mapcar depends on whether the form has been compiled. If it is interpreted, the lambda-expression written above will be passed. If it is compiled, an automatically-generated atomic symbol with the compiled code for the lambda-expression as its subr property will be passed. The usual thing to do with functional arguments is to invoke them via apply or funcall, which accept both the compiled and the interpreted functional forms. function makes no attempt to solve the "funarg problem." *function should be used for this purpose. *function FSUBR The value of (*function f) is a "funarg" of the function f. A funarg can be used like a function. It has the additional property that it contains a binding context pointer so that the values of variables are bound the same during the application of the funarg as at the time it was created, provided that the binding environment in which the funarg was created still exists on the stack. Hence if foo is a function that accepts a functional argument, such as (defun foo (f) (append one-value (f the-other-value) )) or, better (defun foo (f) (append one-value (funcall f the-other-value) )) then (foo (*function bar)) works, but (foo (prog (x y z) (do something) (return (*function bar)) )) does not if bar intends to reference the prog variables x, y, and z. *function is intended to help solve the "funarg problem," however it only works in some easy cases. Funargs generated by *function are intended for use as functional arguments and cannot be returned as values of functional applications. Thus, the user should be careful in his use of *function to make sure that his use does not exceed the limitations of the Maclisp funarg mechanism. It is possible to assign a value to a variable when a previous binding of that variable has been made current by a funarg. The assignment will be executed in the proper context. (This has not always been the case in Maclisp; it is a fairly new feature.) A funarg has the form comment FSUBR comment ignores its arguments and returns the atomic symbol comment. Example: (defun foo (x) (cond ((null x) 0) (t (comment x has something in it) (1+ (foo (cdr x)))))) Usually it is preferable to comment code using the semicolon-macro feature of the standard input syntax. This allows the user to add comments to his code which are ignored by the lisp reader. Example: (defun foo (x) (cond ((null x) 0) (t (1+ (foo (cdr x)))) ;x has something in it )) A problem with such comments is that they are discarded when the S- expression is read into lisp. If it is edited within lisp and printed back into a file, the comments will be lost. However, most users edit the original file and read the changes into lisp, since this allows them to use the editor of their choice. Thus this is not a real problem. prog2 LSUBR 2 or more args The expressions in a prog2 form are evaluated from left to right, as in any lsubr-form. The result is the second argument. prog2 is most commonly used to evaluate an expression with side effects, then return a value which needs to be computed before the side effects happen. Examples: (prog2 (do-this) (do-that)) ;just get 2 things evaluated (setq x (prog2 nil y ;parallel assignment (setq y x))) ;which exchanges x and y (defun prog2 nargs (arg 2)) ;a lexpr definition for prog2 progn LSUBR 1 or more args The expressions in a progn form are evaluated from left to right, as usual, and the result is the value of the last one. In other words, progn is an lsubr which does nothing but return its last argument. Although lambda- expressions, prog-forms, do-forms, cond-forms, and iog-forms all use progn implicitly, that is, they allow multiple forms in their bodies, there are occasions when one needs to evaluate a number of forms for side-effects and make them appear to be a single form. progn serves this purpose. Example: (progn (setq a (cdr frob)) (eq (car a) (cadr a))) might be used as the antecedent of a cond clause. progn could have been defined by: (defun progn nargs (and (> nargs 0) (arg nargs))) progv FSUBR progv is a special form to provide the user with extra control over lambda- binding. It binds a list of variables to a list of values, and then evaluates some forms. The lists of variables and values are computed quantities; this is what makes progv different from lambda, prog, and do. (progv var-list value-list form1 form2 ... ) first evaluates var-list and value-list. Then the variables are bound to the values. In compiled code the variables must be special, since the compiler has no way of knowing what symbols might appear in the var-list. If too few values are supplied, the remaining variables are bound to nil. If too many values are supplied, the excess values are ignored. After the variables have been bound to the values, the forms are evaluated, and finally the variable bindings are undone. The result returned is the value of the last form. Note that the "body" of a progv is similar to that of progn, not that of prog. Example: (setq a 'foo b 'bar) (progv (list a b 'b) (list b) (list a b foo bar)) => (foo nil bar nil) During the evaluation of the body of this progv, foo is bound to bar, bar is bound to nil, b is bound to nil, and a remains bound to foo. arg SUBR 1 arg (arg nil), when evaluated during the application of a lexpr, gives the number of arguments supplied to that lexpr. This is primarily a debugging aid, since lexprs also receive their number of arguments as the value of their lambda-variable. (arg i), when evaluated during the application of a lexpr, gives the value of the i'th argument to the lexpr. i must be a fixnum in this case. It is an error if i is less than 1 or greater than the number of arguments supplied to the lexpr. Example: (defun foo nargs ;define a lexpr foo. (print (arg 2)) ;print the second argument. (+ (arg 1) ;return the sum of the first (arg (- nargs 1)))) ;and next to last arguments. setarg SUBR 2 args setarg is used only during the application of a lexpr. (setarg i x) sets the lexpr's i'th argument to x. i must be greater than zero and not greater than the number of arguments passed to the lexpr. After (setarg i x) has been done, (arg i) will return x. listify SUBR 1 arg (listify n) efficiently manufactures a list of n of the arguments of a lexpr. With a positive argument n, it returns a list of the first n arguments of the lexpr. With a negative argument n, it returns a list of the last (abs n) arguments of the lexpr. Basically, it works as if defined as follows: (defun listify (n) (cond ((minusp n) (listify1 (arg nil) (+ (arg nil) n 1))) (t (listify1 n 1)) )) (defun listify1 (n m) ; auxiliary function. (do ((i n (1- i)) (result nil (cons (arg i) result))) ((< i m) result) )) funcall LSUBR 1 or more args (funcall f a1 a2 ... an) calls the function f with the arguments a1, a2, ..., an. It is similar to apply except that the separate arguments are given to funcall, rather than a list of arguments. If f is a fexpr or an fsubr there must be exactly one argument. f may not be a macro. Example: (setq cons 'plus) (cons 1 2) => (1 . 2) (funcall cons 1 2) => 3 subrcall FSUBR subrcall is used to invoke a subr-pointer directly, rather than by referring to an atomic symbol of which the subr-pointer is the subr property. The form is: (subrcall type p a1 a2 ... an) All arguments except the first are evaluated. type is the type of result expected: fixnum, flonum, or nil (any type). p is the subr pointer to be called. a1 through an are the arguments to be passed to the subr. subrcall compiles into efficient machine code. lsubrcall FSUBR lsubrcall is identical to subrcall except that the subr-pointer called has to be an lsubr instead of a subr. This is because many Lisps use different internal calling sequences for lsubrs than for subrs. arraycall FSUBR arraycall is similar to subrcall and lsubrcall except that an array-pointer is used instead of a subr-pointer. The first argument of arraycall must correspond to the type that the array was given when it was created. An arraycall expression may be used as the first argument to store. symeval SUBR 1 arg symeval is used to get the value of an atomic symbol, when the particular symbol which will be used is not known when the program is written, (for example in a language interpreter written in Lisp.) If the argument to symeval is not an atomic symbol, or is an atomic symbol but does not currently have a value, an error is signalled. The advantage of symeval over eval is that it is compiled into very efficient code (which will not detect the above-mentioned error, so watch out.)  file: LISP, node: Manipulating List Structure, previous: The Evaluator, up: Function Descriptions, next: Conses, Source: MACLISP Manual 3/6/76 * MENU: * Conses:: * Lists:: * Alteration of List Structure:: * Tables:: * Sorting::  file: LISP, node: Conses, previous: Manipulating List Structure, up: Manipulating List Structure, next: Lists, Source: MACLISP Manual 3/6/76 car SUBR 1 arg Returns the first component of a cons. Example: (car '(a b)) => a cdr SUBR 1 arg Returns the second component of a cons. Example: (cdr '(a b c)) => (b c) car SWITCH cdr SWITCH Officially car and cdr are only applicable to lists. However, as a matter of convenience the car and cdr of nil are nil. This allows programs to car and cdr off the ends of lists without having to check, which is sometimes helpful. Furthermore, some old programs apply car and cdr to objects other than lists in order to hack with the internal representation. To provide control over this, the value of car can be set to control which data types are subject to the car operation. Similarly, the value of cdr controls the cdr operation. Illegal operations will cause errors. For reasons of efficiency, this error checking is only enabled in (*rset t) mode (see part 3.5) and is mostly turned off in compiled programs. The values to which the switches may be set are: Value Operation applicable to list lists. nil lists and nil. symbol lists, nil, and symbols. t anything. The default value of the switches is nil. c...r SUBR 1 arg All the compositions of up to four car's and cdr's are defined as functions in their own right. The names begin with c and end with r, and in between is a sequence of a's and d's corresponding to the composition performed by the function. For example, (cddadr x) = (cdr (cdr (car (cdr x)))) Some of the most commonly used ones are: cadr, which gets the second element of a list; caddr, which gets the third element of a list; cadddr, which gets the fourth element of a list; caar, to car twice. The car'ing and cdr'ing operations of these functions have error checking under the control of the car and cdr switches explained above, just as the car and cdr functions themselves do. cons SUBR 2 args This is a primitive function to construct a new dotted pair whose car is the first argument to cons, and whose cdr is the second argument to cons. Thus the following identities hold (except when numbers are involved; as always numbers are not well-behaved with respect to eq): (eq (car (cons x y)) x) => t (eq (cdr (cons x y)) y) => t Examples: (cons 'a 'b) => (a . b) (cons 'a (cons 'b (cons 'c nil))) => (a b c) (cons 'a '(b c d e f)) => (a b c d e f) ncons SUBR 1 arg (ncons x) = (cons x nil) = (list x) xcons SUBR 2 args xcons ("exchange cons") is like cons except that the order of arguments is reversed. Example: (xcons 'a 'b) => (b . a)  file: LISP, node: Lists, previous: Conses, up: Manipulating List Structure, next: Alteration of List Structure, Source: MACLISP Manual 3/6/76 last SUBR 1 arg last returns the last cons of the list which is its argument. Example: (setq x '(a b c d)) (last x) => (d) (rplacd (last x) '(e f)) x => (a b c d e f) last could have been defined by: (defun last (x) (cond ((null x) x) ((null (cdr x)) x) ((last (cdr x))) )) In some implementations, the null check above may be replaced by an atom check, which will catch dotted lists. Code which depends on this fact should not be written though, because all implementations are subject to change on this point. length SUBR 1 arg length returns the length of its argument, which must be a list. The length of a list is the number of top-level conses in it. Examples: (length nil) => 0 (length '(a b c d)) => 4 (length '(a (b c) d)) => 3 length could have been defined by: (defun length (x) (cond ((null x) 0) ((1+ (length (cdr x)))) )) or by: (defun length (x) (do ((n 0 (1+ n)) (y x (cdr y))) ((null y) n) )) The warning about dotted lists given under last applies also to length. list LSUBR 0 or more args list constructs and returns a list of its arguments. Example: (list 3 4 'a (car '(b . c)) (+ 6 -2)) => (3 4 a b 4) list could have been defined by: (defun list nargs (do ((n nargs (1- n)) (s nil (cons (arg n) s))) ((zerop n) s) )) (This depends on parallel assignment to the control variables of do.) append LSUBR 0 or more args The arguments to append are lists. The result is a list which is the concatenation of the arguments. The arguments are not changed (cf. nconc). For example, (append '(a b c) '(d e f) nil '(g)) => (a b c d e f g) To make a copy of the top level of a list, that is, to copy the list but not its elements, use (append x nil). A version of append which only accepts two arguments could have been defined by: (defun append2 (x y) (cond ((null x) y) ((cons (car x) (append2 (cdr x) y)) ))) The generalization to any number of arguments could then be made using a lexpr: (defun append argcount (do ((i (1- argcount) (1- i)) (val (arg argcount) (append2 (arg i) val))) ((zerop i) val) )) reverse SUBR 1 arg Given a list as argument, reverse creates a new list whose elements are the elements of its argument taken in reverse order. reverse does not modify its argument, unlike nreverse which is faster but does modify its argument. Example: (reverse '(a b (c d) e)) => (e (c d) b a) reverse could have been defined by: (defun reverse (x) (do ((l x (cdr l)) ; scan down argument, (r nil ; putting each element (cons (car l) r))) ; into list, until ((null l) r))) ; no more elements. nconc LSUBR 0 or more args nconc takes lists as arguments. It returns a list which is the arguments concatenated together. The arguments are changed, rather than copied. (cf. append) Example: (nconc '(a b c) '(d e f)) => (a b c d e f) Note that the constant (a b c) has now been changed to (a b c d e f). If this form is evaluated again, it will yield (a b c d e f d e f). This is a danger you always have to watch out for when using nconc. nconc could have been defined by: (defun nconc (x y) ;for simplicity, this definition (cond ((null x) y) ;only works for 2 arguments. (t (rplacd (last x) y) ;hook y onto x x))) ;and return the modified x. nreverse SUBR 1 arg nreverse reverses its argument, which should be a list. The argument is destroyed by rplacd's all through the list (cf. reverse). Example: (nreverse '(a b c)) => (c b a) nreverse could have been defined by: (defun nreverse (x) (cond ((null x) nil) ((nreverse1 x nil)))) (defun nreverse1 (x y) ;auxiliary function (cond ((null (cdr x)) (rplacd x y)) ((nreverse1 (cdr x) (rplacd x y))))) ;; this last call depends on order of argument evaluation. nreconc SUBR 2 args (nreconc x y) is exactly the same as (nconc (nreverse x) y) except that it is more efficient. nreconc could have been defined by: (defun nreconc (x y) (cond ((null x) y) ((nreverse1 x y)) )) using the same nreverse1 as above.  file: LISP, node: Alteration of List Structure, previous: Lists, up: Manipulating List Structure, next: Tables, Source: MACLISP Manual 3/6/76 The functions rplaca and rplacd are used to make alterations in already- existing list structure. The structure is not copied but physically altered; hence caution should be exercised when using these functions as strange side- effects can occur if portions of list structure become shared unbeknownst to the programmer. The nconc, nreverse, and nreconc functions already described have the same property. However, they are normally not used for this side-effect; rather, the list-structure modification is purely for efficiency and compatible non-modifying functions are provided. rplaca SUBR 2 args (rplaca x y) changes the car of x to y and returns (the modified) x. Example: (setq g '(a b c)) (rplaca (cdr g) 'd) => (d c) Now g => (a d c) rplacd SUBR 2 args (rplacd x y) changes the cdr of x to y and returns (the modified) x. Example: (setq x '(a b c)) (rplacd x 'd) => (a . d) Now x => (a . d) See also setplist (page 2-51). subst SUBR 3 args (subst x y z) substitutes x for all occurrences of y in z, and returns the modified copy of z. The original z is unchanged, as subst recursively copies all of z replacing elements eq to y as it goes. If x and y are nil, z is just copied, which is a convenient way to copy arbitrary list structure. Example: (subst 'Tempest 'Hurricane '(Shakespeare wrote (The Hurricane))) => (Shakespeare wrote (The Tempest)) subst could have been defined by: (defun subst (x y z) (cond ((eq z y) x) ;if item eq to y, replace. ((atom z) z) ;if no substructure, return arg. ((cons (subst x y (car z)) ;otherwise recurse. (subst x y (cdr z)))))) sublis SUBR 2 args sublis makes substitutions for atomic symbols in an S-expression. The first argument to sublis is an association list (see the next section). The second argument is the S-expression in which substitutions are to be made. sublis looks at all atomic symbols in the S-expression; if an atomic symbol appears in the association list occurrences of it are replaced by the object it is associated with. The argument is not modified; new conses are created where necessary and only where necessary, so the newly created structure shares as much of its substructure as possible with the old. For example, if no substitutions are made, the result is eq to the old S- expression. Example: (sublis '((x . 100) (z . zprime)) '(plus x (minus g z x p) 4)) => (plus 100 (minus g zprime 100 p) 4) In some implementations sublis works by putting temporary sublis properties  file: LISP, node: Tables, previous: Alteration of List Structure, up: Manipulating List Structure, next: Sorting, Source: MACLISP Manual 3/6/76 Maclisp includes several functions which simplify the maintenance of tabular data structures of several varieties. The simplest is a plain list of items, which models (approximately) the concept of a set. There are functions to add (cons), remove (delete, delq), and search for (member, memq) items in a list. Association lists are very commonly used. An association list is a list of dotted pairs. The car of each pair is a "key" and the cdr is "data". The functions assoc and assq may be used to retrieve the data, given the key. Structured records can be stored as association lists or as stereotyped S- expressions where each element of the structure has a certain car-cdr path associated with it. There are no built-in functions for these but it easy to define macros to implement them (see part 6.2). Simple list-structure is very convenient, but may not be efficient enough for large data bases because it takes a long time to search a long list. Maclisp includes some hashing functions (sxhash, maknum) which aid in the construction of more efficient, hairier structures. member SUBR 2 args (member x y) returns nil if x is not a member of the list y. Otherwise, it returns the portion of y beginning with the first occurrence of x. The comparison is made by equal. y is searched on the top level only. Example: (member 'x '(1 2 3 4)) => nil (member 'x '(a (x y) c x d e x f)) => (x d e x f) Note that the value returned by member is eq to the portion of the list beginning with x. Thus rplaca on the result of member may be used, if you first check to make sure member did not return nil. Example: (catch (rplaca (or (member x z) (throw nil lose)) y) member could have been defined by: (defun member (x y) (cond ((null y) nil) ((equal x (car y)) y) ((member x (cdr y))) )) memq SUBR 2 args memq is like member, except eq is used for the comparison, instead of equal. memq could have been defined by: (defun memq (x y) (cond ((null y) nil) ((eq x (car y)) y) ((memq x (cdr y))) )) delete LSUBR 2 or 3 args (delete x y) returns the list y with all top-level occurrences of x removed. equal is used for the comparison. The argument y is actually modified (rplacd'ed) when instances of x are spliced out. delete should be used for value, not for effect. That is, use (setq a (delete 'b a)) rather than (delete 'b a)) The latter is not equivalent when the first element of the value of a is b. (delete x y n) is like (delete x y) except only the first n instances of x are deleted. n is allowed to be zero. If n is greater than the number of occurrences of x in the list, all occurrences of x in the list will be deleted. Example: (delete 'a '(b a c (a b) d a e)) => (b c (a b) d e) delete could have been defined by: (defun delete nargs ; lexpr for 2 or 3 args (delete1 (arg 1) ; pass along arguments... (arg 2) (cond ((= nargs 3) (arg 3)) (123456789.)))) ; infinity (defun delete1 (x y n) ;auxiliary function (cond ((or (null y) (zerop n)) y) ((equal x (car y)) (delete1 x (cdr y) (1- n))) ((rplacd y (delete1 x (cdr y) n))))) delq LSUBR 2 or 3 args delq is the same as delete except that eq is used for the comparison instead of equal. sxhash SUBR 1 arg sxhash computes a hash code of an S-expression, and returns it as a fixnum, which may be positive or negative. A property of sxhash is that (equal x y) implies (= (sxhash x) (sxhash y)). The number returned by sxhash is some possibly large number in the range allowed by fixnums. It is guaranteed that: 1) sxhash for an atomic symbol will always be positive. 2) sxhash of any particular expression will be constant in a particular implementation for all time, probably. 3) Two different implementations may hash the same expression into different values. 4) sxhash of any object of type random will be zero. 5) sxhash of a fixnum will = that fixnum. Here is an example of how to use sxhash in maintaining hash tables of S-expressions: (defun knownp (x) ;look up x in the table (prog (i bkt) (setq i (plus 76 (remainder (sxhash x) 77))) ;The remainder should be reasonably randomized between ;-76 and 76, thus table size must be > 175 octal. (setq bkt (table i)) ;bkt is thus a list of all those expressions that hash ;into the same number as does x. (return (member x bkt)))) To write an "intern" for S-expressions, one could (defun sintern (x) (prog (bkt i tem) (setq bkt (table (setq i (+ 2n-2 (\ (sxhash x) 2n-1))))) ;2n-1 and 2n-1 stand for a power of 2 minus one and ;minus two respectively. This is a good choice to ;randomize the result of the remainder operation. (return (cond ((setq tem (member x bkt)) (car tem)) (t (store (table i) (cons x bkt)) x))))) assoc SUBR 2 args (assoc x y) looks up x in the association list (list of dotted pairs) y. The value is the first dotted pair whose car is equal to x, or nil if there is none such. Examples: (assoc 'r '((a . b) (c . d) (r . x) (s . y) (r . z))) => (r . x) (assoc 'fooo '((foo . bar) (zoo . goo))) => nil It is okay to rplacd the result of assoc as long as it is not nil, if your Example: (setq values '((x . 100) (y . 200) (z . 50))) (assoc 'y values) => (y . 200) (rplacd (assoc 'y values) 201) (assoc 'y values) => (y . 201) now (One should always be careful about using rplacd however) A typical trick is to say (cdr (assoc x y)). Since the cdr of nil is guaranteed to be nil, this yields nil if no pair is found (or if a pair is found whose cdr is nil.) assoc could have been defined by: (defun assoc (x y) (cond ((null y) nil) ((equal x (caar y)) (car y)) ((assoc x (cdr y))) )) assq SUBR 2 args assq is like assoc except that the comparison uses eq instead of equal. assq could have been defined by: (defun assq (x y) (cond ((null y) nil) ((eq x (caar y)) (car y)) ((assq x (cdr y))) )) sassoc SUBR 3 args (sassoc x y z) is like (assoc x y) except that if x is not found in y, instead of returning nil sassoc calls the function z with no arguments. sassoc could have been defined by: (defun sassoc (x y z) (or (assoc x y) (apply z nil))) sassoc and sassq (see below) are of limited use. These are primarily sassq SUBR 3 args (sassq x y z) is like (assq x y) except that if x is not found in y, instead of returning nil sassq calls the function z with no arguments. sassq could have been defined by: (defun sassq (x y z) (or (assq x y) (apply z nil))) maknum SUBR 1 arg (maknum x) returns a positive fixnum which is unique to the object x; that is, (maknum x) and (maknum y) are numerically equal if and only if (eq x y). This can be used in hashing. In the pdp-10 implementations, maknum returns the memory address of its argument. In the Multics implementation, an internal hash table is employed. Note that unlike sxhash, maknum will not return the same value on an expression which has been printed out and read back in again. munkam SUBR 1 arg munkam is the opposite of maknum. Given a number, it returns the object which was given to maknum to get that number. It is inadvisable to apply munkam to a number which did not come from maknum.  file: LISP, node: Sorting, previous: Tables, up: Manipulating List Structure, next: Flow of Control, Source: MACLISP Manual 3/6/76 Several functions are provided for sorting arrays and lists. These functions use algorithms which always terminate no matter what sorting predicate is used, provided only that the predicate always terminates. The array sort is not necessarily stable, that is equal items may not stay in their original order. However the list sort is stable. After sorting, the argument (be it list or array) is rearranged internally so as to be completely ordered. In the case of an array argument, this is accomplished by permuting the elements of the array, while in the list case, the list is reordered by rplacd's in the same manner as nreverse. Thus if the argument should not be clobbered, the user must sort a copy of the argument, obtainable by fillarray or append, as appropriate. Should the comparison predicate cause an error, such as a wrong type argument error, the state of the list or array being sorted is undefined. However, if the error is corrected the sort will, of course, proceed correctly. Both sort and sortcar handle the case in which their second argument is the function alphalessp in a more efficient manner than usual. This efficiency is primarily due to elimination of argument checks at comparison time. sort SUBR 2 args The first argument to sort is an array (or list), the second a predicate of two arguments. Note that a "number array" cannot be sorted. The predicate must be applicable to all the objects in the array or list. The predicate should take two arguments, and return non-nil if and only if the first argument is strictly less than the second (in some appropriate sense). The sort function proceeds to sort the contents of the array or list under the ordering imposed by the predicate, and returns the array or list modified into sorted order, i.e. its modified first argument. Note that since sorting requires many comparisons, and thus many calls to the predicate, sorting will be much faster if the predicate is a compiled function rather than interpreted. Example: (defun mostcar (x) (cond ((atom x) x) ((mostcar (car x))))) (sort 'fooarray (function (lambda (x y) (alphalessp (mostcar x) (mostcar y))))) If fooarray contained these items before the sort: (Tokens (The lion sleeps tonight)) (Carpenters (Close to you)) ((Rolling Stones) (Brown sugar)) ((Beach Boys) (I get around)) (Beatles (I want to hold your hand)) then after the sort fooarray would contain: ((Beach Boys) (I get around)) (Beatles (I want to hold your hand)) (Carpenters (Close to you)) ((Rolling Stones) (Brown sugar)) (Tokens (The lion sleeps tonight)) sortcar SUBR 2 args sortcar is exactly like sort, but the items in the array or list being sorted should all be non-atomic. sortcar takes the car of each item before handing two items to the predicate. Thus sortcar is to sort as mapcar is to maplist.  file: LISP, node: Flow of Control, previous: Sorting, up: Function Descriptions, next: Conditionals, Source: MACLISP Manual 3/6/76 * MENU: * Conditionals:: * Iteration:: * Non-local Exits:: * Causing and Controlling Errors:: Maclisp provides a variety of structures for flow of control. Functional application is the basic method for construction of programs. All operations are written as the application of a function to arguments. Maclisp programs are often written as a large collection of small functions which implement simple operations. Some of the functions work by calling others of the functions, thus defining some operations in terms of others. Recursion exists when a function calls itself. This is analogous to mathematical induction. Iteration is a control structure present in most languages. It is similar to recursion but sometimes less useful and sometimes more useful. Maclisp contains a generalized iteration facility. The iteration facility also permits those who like "gotos" to use them. Conditionals allow control to branch depending on the value of a predicate. and and or are basically one-arm conditionals, while cond is a generalized multi-armed conditional. Nonlocal exits are similar to a return, except that the return is from several levels of function calling rather than just one, and is determined at run time. These are mostly used for applications such as escaping from the middle of a function when it is discovered that the algorithm is not applicable. Errors are a type of non-local exit used by the Lisp interpreter when it discovers a condition that it does not like. Errors have the additional feature of correctability, which allows a user-specified function (most often a break loop), to get a chance to come in and correct the error or at least inspect what was happening and determine what caused it, before the nonlocal exit occurs. This is explained in detail on part 3.4. Maclisp does not directly provide "hairy control structure" such as multiple processes, backtracking, or continuations.  file: LISP, node: Conditionals, previous: Flow of Control, up: Flow of Control, next: Iteration, Source: MACLISP Manual 3/6/76 and FSUBR (and form1 form2...) evaluates the forms one at a time, from left to right. If any form evaluates to nil, and immediately returns nil without evaluating the remaining forms. If all the forms evaluate non-nil, and returns the value of the last one. and can be used both for logical operations, where nil stands for False and t stands for True, and as a conditional expression. Examples: (and x y) (and (setq temp (assq x y)) (rplacd temp z)) (and (null (errset (something))) (princ "There was an error.")) Note: (and) => t, which is the identity for this operation. or FSUBR (or form1 form2...) evaluates the forms one by one from left to right. If a form evaluates to nil, or proceeds to evaluate the next form. If there are no more forms, or returns nil. But if a form evaluates non-nil, or immediately returns that value without evaluating any remaining forms. or can be used both for logical operations, where nil stands for False and t for True, and as a conditional expression. Note: (or) => nil, the identity for this operation. cond FSUBR The cond special form consists of the word cond followed by several clauses. Each clause consists of a predicate followed by zero or more forms. Sometimes the predicate is called the antecedent and the forms are called the consequents. (cond (antecedent consequent consequent...) (antecedent ...) ... ) The idea is that each clause represents a case which is selected if its predicate is satisfied and the predicates of all preceding clauses are not satisfied. When a case is selected, its consequent forms are evaluated. cond processes its clauses in order from left to right. First the predicate of the current clause is evaluated. If the result is nil, cond advances to the next clause. Otherwise, the cdr of the clause is treated as a list of forms, or consequents, which are evaluated in order from left to right. After evaluating the consequents, cond returns without inspecting any remaining clauses. The value of the cond special form is the value of the last consequent evaluated, or the value of the antecedent if there were no consequents in the clause. If cond runs out of clauses, that is, if every antecedent is nil, that is, if no case is selected, the value of the cond is nil. Example: (cond ((zerop x) ;First clause: (+ y 3)) ; (zerop x) is antecedent. ; (+ y 3) is consequent. ((null y) ;A clause with 2 consequents: (setq x 4) ; this (cons x z)) ; and this. (z) ;A clause with no consequents: ; the antecedent is just z. ) ;This is the end of the cond. This is like the traditional Lisp 1.5 cond except that it is not necessary to have exactly one consequent in each clause, and it is permissible to run out of clauses.  file: LISP, node: Iteration, previous: Conditionals, up: Flow of Control, next: Non-local Exits, Source: MACLISP Manual 3/6/76 prog FSUBR prog is the "program" special form. It provides temporary variables, sequential evaluation of statements, and the ability to do "gotos." A prog looks something like: (prog (var1 var2...) tag1 statement1 statement2 tag2 statement3 . . . ) var1, var2, ... are temporary variables. When the prog is entered the values of these variables are saved. When the prog is exited they are restored. The variables are initialized to nil when the prog is entered, thus they are said to be "bound to nil" by the prog. However, variables which have been declared fixnum or flonum will be initialized to 0 or 0.0 instead, but only in compiled programs. You should be careful about relying on the initial value of prog-variables. The part of a prog after the temporary variable list is the body. An item in the body may be an atomic symbol or a number, which is a tag, or a non- atomic form, which is a statement. prog, after binding the temporary variables, processes its body sequentially. tags are skipped over; statements are evaluated but the values are ignored. If the end of the body is reached, prog returns nil. If (return x) is evaluated, prog stops processing its body and returns the value x. If (go tag) is evaluated, prog jumps to the part of the body labelled with the tag. The argument to go is not evaluated unless it is non-atomic. It should be noted that the Maclisp prog is an extension of the Lisp 1.5 prog, in that go's and return's may occur in more places than Lisp 1.5 allowed. However, the Lisp compilers implemented on ITS, Multics, and the DECsystem 10 for Maclisp require that go's and return's be lexically within the scope of the prog. This makes a function which does not contain a prog, but which does contain a go or return uncompilable. See also the do special form, which uses a body similar to prog. The do, catch, and throw special forms are included in Maclisp as an attempt to encourage goto-less programming style, which leads to more readable, more easily maintained code. The programmer is recommended to use these functions instead of prog wherever reasonable. Example: (prog (x y z) ;x, y, z are prog variables - temporaries. (setq y (car w) z (cdr w)) ;w is a free variable. loop (cond ((null y) (return x)) ((null z) (go err))) rejoin (setq x (cons (cons (car y) (car z)) x)) (setq y (cdr y) z (cdr z)) (go loop) err (break are-you-sure? t) (setq z y) (go rejoin)) do FSUBR The do special form provides a generalized "do loop" facility, with an arbitrary number of "index variables" whose values are saved when the do is entered and restored when it is left, i.e. they are bound by the do. The index variables are used in the iteration performed by do. At the beginning they are initialized to specified values, and then at the end of each trip around the loop the values of the index variables are changed according to specified rules. do allows the programmer to specify a predicate which determines when the iteration will terminate. The value to be returned as the result of the form may optionally be specified. do comes in two varieties. The newer variety of do looks like: (do ((var init repeat)...) (end-test exit-form...) body...) The first item in the form is a list of zero or more index variable specifiers. Each index variable specifier is a list of the name of a variable var, an initial value init, which defaults to nil (or possibly zero, as mentioned under prog) if it is omitted, and a repeat value repeat. If repeat is omitted, the var is not changed between loops. All assignment to the index variables is done in parallel. At the beginning of the first iteration, all the inits are evaluated, then the vars are saved, then the vars are setq'ed to the values of the inits. To put it another way, the vars are lambda-bound to the values of the inits. Note that the inits are evaluated before the vars are bound. At the beginning of each succeeding iteration those vars that have repeats get setq'ed to the values of their respective repeats. Note that all the repeats are evaluated before any of the vars is changed. The second element of the do-form is a list of an end testing predicate end-test and zero or more forms, the exit-forms. At the beginning of each iteration, after processing of the repeats, the end-test is evaluated. If the result is nil, execution proceeds with the body of the do. If the result is not nil, the exit-forms are evaluated from left to right and then do returns. The value of the do is the value of the last exit-form, or nil if there were no exit-forms. Note that the second element of the do-form resembles a cond clause. If the second element of the form is nil, there is no end-test nor exit- forms, and the body of the do is executed only once. In this type of do it is an error to have repeats. This type of do is a "prog with initial values." If the second element of the form is the S-expression (nil), there is no end-test or exit-forms, and the body of the do is executed over and over. This is a "do forever." The infinite loop can be terminated by use of return or throw. The remainder of the do-form constitutes a prog-body. When the end of the body is reached, the next iteration of the do begins. If return is used, The older variety of do is: (do var init repeat end-test body...) The first time through the loop var gets the value of init; the remaining times through the loop it gets the value of repeat, which is re-evaluated each time. Note that init is evaluated before the value of var is saved. After var is set, end-test is evaluated. If it is non-nil, the do finishes and returns nil. If the end-test is nil, the body of the loop is executed. The body is like a prog body. go may be used. If return is used, its argument is the value of the do. If the end of the prog body is reached, another loop begins. Examples of the older variety of do: (setq n (cadr (arraydims x))) (do i 0 (1+ i) (= i n) (store (x i) 0)) ;zeroes out the array x (do zz x (cdr zz) (or (null zz) (zerop (f (car zz))))) ; this applies f to each element of x ; continuously until f returns zero. Examples of the new form of do: (do ((n (cadr (arraydims x))) (i 0 (1+ i))) ((= i n) (store (x i) 0)) ;this is like the example above, ;except n is local to the do (do ((x) (y) (z)) (nil) body) is like (prog (x y z) body) except that when it runs off the end of the body, do loops but prog returns nil. On the other hand, (do ((x) (y) (z)) nil body) is identical to the prog above (it does not loop.) (do ((x y (f x))) ((p x)) body) is like (do x y (f x) (p x) body) The construction (do ((x e (cdr x)) (oldx x x)) ((null x)) body) exploits parallel assignment to index variables. On the first iteration, the value of oldx is whatever value x had before the do was entered. On succeeding iterations, oldx contains the value that x had on the previous iteration. In either form of do, the body may contain no forms at all. Very often an iterative algorithm can be most clearly expressed entirely in the repeats and exit-forms of a new-style do, and the body is empty. (do ((x x (cdr x)) (y y (cdr y)) (z nil (cons (f x y) z))) ;exploits parallel ((or (null x) (null y)) ; assignment. (nreverse z)) ;typical use of nreverse. ) ;no do-body required. is like (maplist 'f x y). go FSUBR The (go tag) special form is used to do a "go-to" within the body of a do or a prog. If the tag is an atom, it is not evaluated. Otherwise it is evaluated and should yield an atom. Then go transfers control to the point in the body labelled by a tag eq or = to the one given. (Tags may be either atomic symbols or numbers). If there is no such tag in the body, it is an unseen-go-tag error. "Computed" go's should be avoided in compiled code, or altogether. Example: (prog (x y z) (setq x some frob) loop do something (and some predicate (go loop)) ;regular go do something more (go (cond ((minusp x) 'loop) ;"computed go" (t 'endtag))) endtag (return z)) return SUBR 1 arg return is used to return from a prog or a do. The value of return's argument is returned by prog or do as its value. In addition, break recognizes the typed-in S-expression (return value) specially. If this form is typed at a break, value will be evaluated and returned as the value of break. If not at the top level of a form typed at a break, and not inside a prog or do, return will cause a fail-act error. Example: (do ((x x (cdr x)) (n 0 (* n 2))) ((null x) n) (cond ((atom (car x)) (setq n (1+ n))) ((memq (caar x) '(sys boom bleah)) (return n))))  file: LISP, node: Non-local Exits, previous: Iteration, up: Flow of Control, next: Causing and Controlling Errors, Source: MACLISP Manual 3/6/76 catch FSUBR catch is the Maclisp function for doing structured non-local exits. (catch x) evaluates x and returns its value, except that if during the evaluation of x (throw y) should be evaluated, catch immediately returns y without further evaluating x. catch may also be used with a second argument, not evaluated, which is used as a tag to distinguish between nested catches. (catch x b) will catch a (throw y b) but not a (throw y z). throw with only one argument always throws to the innermost catch. catch with only one argument catches any throw. It is an error if throw is done when there is no suitable catch. Example: (catch (mapcar (function (lambda (x) (cond ((minusp x) (throw x negative)) (t (f x))))) y) negative) which returns a list of f of each element of y if y is all positive, otherwise the first negative member of y. The user of catch and throw is advised to stick to the 2 argument versions, which are no less efficient, and tend to reduce the likelihood of bugs. The one argument versions exist primarily as an easy way to fix old Lisp programs which use errset and err for non-local exits. This latter practice is rather confusing, because err and errset are supposed to be used for error handling, not general program control. The catch-tag break is used by the break function. throw FSUBR throw is used with catch as a structured non-local exit mechanism. (throw x) evaluates x and throws the value back to the most recent catch. (throw x tag) throws the value of x back to the most recent catch labelled with tag or unlabelled. catch'es with tags not eq to tag are skipped over. x is evaluated but tag is not. See the description of catch for further details.  file: LISP, node: Causing and Controlling Errors, previous: Non-local Exits, up: Flow of Control, next: Atomic Symbols, Source: MACLISP Manual 3/6/76 See the complete description of the Maclisp error system (part 3.4) for more information about how these functions work. error LSUBR 0 to 3 args This is a function which allows user functions to signal their own errors using the Maclisp error system. (error) is the same as (err). (error message) signals a simple error; no datum is printed and no user interrupt is signalled. The error message typed out is message. (error message datum) signals an error with message as the message to be typed out and datum as the Lisp object to be printed in the error message. No user interrupt is signalled. (error message datum uint-chn) signals an error but first signals a user interrupt on channel uint-chn, provided that there is such a channel, and it has a non-nil service function, and the special conditions concerning errset (see part 3.4) are satisfied. uint-chn is the name of the user- interrupt channel to be used (an atomic symbol); see part 3.4.2. If the service function returns an atom, error goes ahead and signals a regular error. If the service function returns a list, error returns as its value the car of that list. In this case it was a "correctable" error. This is the only case in which error will return; in all other cases control is thrown back to top level, or to the nearest enclosing errset. errset FSUBR The special form (errset form flag) is used to trap an expected error. errset evaluates the form. If an error occurs during the evaluation of the form, the error is prevented from escaping from inside the errset and errset returns nil. If no errors occur, a list of one element, the result of the evaluation, is returned. The result is listified so that there will no ambiguity if it is nil. errset may also be made to return any arbitrary value by use of the err function. The flag is optional. If present, it is evaluated before the form. If it is nil, no error message will be printed if an error occurs during the evaluation of the form. If it is not nil, or if it is omitted, any error messages generated will be printed. Examples: If you are not sure x is a number: (errset (setq x (add1 x))) This example may not work in compiled code if the compiler chooses to open- code the add1 rather than calling the add1 subroutine. In general, one must be extremely foolhardy to depend on error checking in compiled code. To suppress the error message if the value of a is not an atomic symbol: (errset (set a b) nil) To do the same but generate one's own message: (or (errset (set a b) nil) (error '(not a variable) a)) err FSUBR (err) causes an error which is handled the same as a Lisp error except that there is no preliminary user interrupt, and no message is typed out. (err x) is like (err) except that if control returns to an errset, the value of the errset will be the result of evaluating x, instead of nil. (err x nil) is the same as (err x). (err x t) is like (err x) except that x is not evaluated until just before the errset returns it. That is, x is evaluated after unwinding the pdl and restoring the bindings. Note: some people use err and errset where catch and throw are indicated. This is a very poor programming practice. See writeups of catch and throw for details.  file: LISP, node: Atomic Symbols, previous: Causing and Controlling Errors, up: Function Descriptions, next: The Value Cell, Source: MACLISP Manual 3/6/76 * MENU: * The Value Cell:: * The Property List:: * The Print-Name:: * Interning of Symbols:: * Defining Atomic Symbols as Functions::  file: LISP, node: The Value Cell, previous: Atomic Symbols, up: Atomic Symbols, next: The Property List, Source: MACLISP Manual 3/6/76 Each atomic symbol has associated with it a value cell, which is a piece of storage that can refer to one Lisp object. This object is called the symbol's value, since it is what is returned if the symbol is evaluated. The binding of atomic symbols to values allows them to be used in programming the way "variables" are used in other languages. The value cell can also be empty, in which case the symbol has no value and is said to be unbound or undefined. This is the initial state of a newly- created atomic symbol. Attempting to evaluate an unbound symbol causes an error to be signalled. An object can be placed into a symbol's value cell by lambda-binding or by assignment. (See page 1-11.) The difference is in how closely the value- changing is associated with control structure and in whether it is considered a side-effect. setq FSUBR The setq special form is used to assign values to variables (atomic symbols.) setq processes the elements of its form in pairs, sequentially from left to right. The first member of each pair is a variable, the second is a form which evaluates to a value. The form is evaluated, but the variable is not. The value-binding of the variable is made to be the value specified. You must not setq the special atomic-symbol constants t and nil. The value returned by setq is the last value assigned, i.e. the result of the evaluation of the last element of the setq-form. Example: (setq x (+ 1 2 3) y (cons x nil)) This returns (6) and gives x a value of 6 and y a value of (6). Note that the first assignment is completed before the second assignment is started, resulting in the second use of x getting the value assigned in the set SUBR 2 args set is like setq except that the first argument is evaluated; also set only takes one pair of arguments. The first argument must evaluate to an atomic symbol, whose value is changed to the value of the second argument. set returns the value of its second argument. Example: (set (cond ((predicate) 'atom1) (t 'atom2)) 'stba) evaluates to stba and gives either atom1 or atom2 a value of stba. set could have been defined by: (defun set (x y) (eval (list 'setq x (list 'quote y)))) Alternatively, setq could have been defined by: (defun setq fexpr (x) ((lambda (var val rest) (set var val) (cond ((null rest) val) ((apply (function setq) rest)) )) ;if more, recurse (car x) (eval (cadr x)) (cddr x))) symeval SUBR 1 arg (symeval a) returns the value of a, which must be an atomic symbol. The compiler produces highly optimal code for symeval, making it much better than eval when the value of a symbol needs to be taken and the particular symbol to be used varies. boundp SUBR 1 arg The argument to boundp must be an atomic symbol. If it has a value, t is returned. Otherwise nil is returned. makunbound SUBR 1 arg The argument to makunbound must be an atomic symbol. Its value is removed, i.e. it becomes unbound. Example: (setq a 1) a => 1 (makunbound 'a) a => unbnd-vrbl error. makunbound returns its argument.  file: LISP, node: The Property List, previous: The Value Cell, up: Atomic Symbols, next: The Print-Name, Source: MACLISP Manual 3/6/76 A property-list is a list with an even number of elements. Each pair of elements constitutes a property; the first element is called the "indicator" and the second is called the "value" or, loosely, the "property." The indicator is generally an atomic symbol which serves as the name of the property. The value is any Lisp object. For example, one type of functional property uses the atom expr as its indicator. In the case of an expr-property, the value is a list beginning with lambda. An example of a property list with two properties on it is: (expr (lambda (x) (plus 14 x)) foobar t) The first property has indicator expr and value (lambda (x) (plus 14 x)), the second property has indicator foobar and value t. Each atomic symbol has associated with it a property-list, which can be retrieved with the plist function. It is also possible to have "disembodied" property lists which are not associated with any symbol. These keep the property list on their cdr, so the form of a disembodied property list is ( . plist). The way to create a disembodied property list is (ncons nil). Atomic symbols also (usually) keep their property list on their cdr, but you aren't allowed to know that. Use the plist function to get the property list of a symbol. Property lists are useful for associating "attributes" with symbols. Maclisp uses properties to remember function definitions. The compiler uses properties internally to keep track of some of what it knows about the program it is compiling. The user familiar with Lisp 1.5 will want to note that the property list "flags" which are allowed on Lisp 1.5 property lists do not exist in Maclisp. However, the same effect can be achieved by using properties with a value of t or nil. Some property names are used internally by Maclisp, and should therefore be avoided in user code. These include args, array, autoload, expr, fexpr, fsubr, lsubr, macro, pname, sublis, subr, value, used by the Lisp system proper; arith, *array, atomindex, *expr, *fexpr, *lexpr, numfun, number, numvar, ohome, special, sym, used by the compiler; grindfn, grindmacro, used by the grinder. get SUBR 2 args (get x y) gets x's y-property. x can be an atomic symbol or a disembodied property list. The value of x's y-property is returned, unless x has no y- property in which case nil is returned. It is not an error for x to be a number, but nil will always be returned since numbers do not have property lists. Example: (get 'foo 'bar) => nil ;initially foo has no bar property (putprop 'foo 'zoo 'bar) ;give foo a bar property => zoo (get 'foo 'bar) ;retrieve that property => zoo (plist 'foo) ;look at foo's property list => (bar zoo ...other properties...) get could have been defined by: (defun get (x y) (do ((z (cond ((numberp x) nil) ((atom x) (plist x)) (t (cdr x))) (cddr z))) ((or (null z) (eq y (car z))) (cadr z)))) This relies on the fact that the car and the cdr of nil are nil, and therefore (cadr z) is nil if z is nil. getl SUBR 2 args (getl x y) is like get except that y is a list of indicators rather than just a single indicator. getl searches x's property list until a property whose indicator appears in the list y is found. The portion of x's property list beginning with the first such property is returned. The car of this is the indicator (property name) and the cadr is the property value. getl returns nil if none of the indicators in y appear on the property list of x. getl could have been defined by: (defun getl (x pl) (do ((q (plist x) (cddr q))) ; scan down P-list of x ((or (null q) (memq (car q) pl)) q))) This definition is simplified and doesn't take numbers and disembodied property lists into account. putprop SUBR 3 args (putprop x y z) gives x a z-property of y and returns y. x may be an atomic symbol or a disembodied property list. After somebody does (putprop x y z), (get x z) will return y. Example: (putprop 'Nixon 'not 'crook) If the symbol already has a property with the same name that property is removed first. This ensures that getl will always find the property which was put on most recently. For instance, if you were to redefine an expr as a subr, and then redefine it as an expr again, this effect of putprop causes the evaluator to find the latest definition always. A lisp definition of the basic putprop without the complications of numbers and disembodied property lists might be: (defun putprop (x y z) (remprop x z) (setplist x (cons z (cons y (plist x)))) y) defprop FSUBR defprop is a version of putprop with no argument-evaluation, which is sometimes more convenient for typing. For instance, (defprop foo bar oftenwith) is equivalent to (putprop 'foo 'bar 'oftenwith) remprop SUBR 2 args (remprop x y) removes x's y-property, by splicing it out of x's property list. The value is nil if x had no y-property. If x did have a y- property, the value is a list whose car is the property, and whose cdr is part of x's property list, similar to (cdr (getl x '(y))). x may be an atomic symbol or a disembodied property list. Example: (remprop 'foo 'expr) undefines the function foo, assuming it was defined by (defun foo (x) ... ) plist SUBR 1 arg (plist x) returns the property list of the atomic symbol x. setplist SUBR 2 args (setplist x l) sets the property list of the atomic symbol x to l. This is to be used with caution, since in some implementations property lists contain internal system properties which are essential to the workings of the Lisp system.  file: LISP, node: The Print-Name, previous: The Property List, up: Atomic Symbols, next: Interning of Symbols, Source: MACLISP Manual 3/6/76 Each atomic symbol has an associated character string called its "print- name," or "pname" for short. This character string is used as the external representation of the symbol. If the string is typed in, it is read as a reference to the symbol. If the symbol is to be print'ed, the string is typed out. See also page 2-79 for some other functions which have to do with pnames. samepnamep SUBR 2 args The arguments to samepnamep must evaluate to atomic symbols or to character strings. The result is t if they have the same pname, nil otherwise. The pname of a character string is considered to be the string itself. Examples: (samepnamep 'xyz (maknam '(x y z))) => t (samepnamep 'xyz (maknam '(w x y))) => nil (samepnamep 'x "x") => t alphalessp SUBR 2 args (alphalessp x y), where x and y evaluate to atomic symbols or character strings, returns t if the pname of x occurs earlier in alphabetical order than the pname of y. The pname of a character string is considered to be the string itself. Examples: (alphalessp 'x 'x1) => t (alphalessp 'z 'q) => nil (alphalessp "x" 'y) => t Note that the "alphabetical order" used by alphalessp is actually the ASCII collating sequence. Consequently all upper case letters come before all lower case letters. pnget SUBR 2 args (pnget symbol n) returns the pname of the symbol as a list of fixnums containing packed n-bit bytes. The legal values of n depend on the implementation; in the pdp-10 implementation, 6 (SIXBIT) and 7 (ASCII) are allowed. If this seems obscure, that's because it is. Example: (pnget 'MUMBLERATOR 7) => (-311246236550 -351327625542 -270_33) pnput SUBR 2 args This is a sort of inverse of pnget. (pnput (pnget foo 7) flag) returns a symbol with the same pname as foo. The symbol is interned if flag is non- nil.  file: LISP, node: Interning of Symbols, previous: The Print-Name, up: Atomic Symbols, next: Defining Atomic Symbols as Functions, Source: MACLISP Manual 3/6/76 One normally wants to refer to the same (eq) atomic symbol every time the same pname is typed. Maclisp implements this through what is called the obarray. The obarray is a hash-table of atomic symbols. These symbols are said to be interned, or registered in the obarray. Whenever a pname is read in Lisp input, the obarray is searched for a symbol with the same pname. If one is found, the pname is considered to refer to that symbol. If not, a new symbol is created and added to the obarray. The representation of an obarray is a Lisp array. The first 510. (or thereabouts) elements of the array contain lists which are buckets of a hash table. The last 128. elements of the array contain the "character objects," symbols with 1-character pnames. (These entries contain nil if the corresponding symbol has not yet been interned.) The character objects are treated specially for efficiency. There are usually one or two unused array elements between these two areas. In order to allow for multiple name spaces, Maclisp allows multiple obarrays. An obarray can be made "current" by binding the symbol obarray to the appropriate array-pointer. See page 2-85 for details on how to manipulate obarrays and arrays in general. It is possible to have a symbol interned on several obarrays at the same time. It is also possible to have two different (non-eq) symbols with the same pname interned on different obarrays. Furthermore it is possible to have a symbol which is not interned on any obarray, which is called an uninterned symbol. These are useful for purely-internal functions, but can cause difficulty in debugging since they can't be accessed directly. Such a symbol can be accessed via some data structure that contains it, set up by the program that created it. Normally symbols are never removed from obarrays. It is possible for the user to explicitly remove a symbol from the current obarray. There is also a feature by which "truly worthless" symbols may be removed automatically (see part 3.6). intern SUBR 1 arg (intern x), where x is an atomic symbol, returns the unique atomic symbol which is "interned on the obarray" and has the same pname as x. If no symbol on the current obarray has the same pname as x, then intern will place x itself on the obarray, and return it as the value. remob SUBR 1 arg The argument to remob must be an atomic symbol. It is removed from the current obarray if it is interned on that obarray. This makes the atomic symbol inaccessible to any S-expressions that may be read in or loaded in the future. remob returns nil. copysymbol SUBR 2 args A subr of two arguments. The first argument must be a symbol, and the second should be t or nil. The result is a new, uninterned symbol, with the same pname as the argument. "Uninterned" means that the symbol has not been placed on any obarray. If the second argument is t, the new symbol will be given the same value as the original and will have a copy of its property list. Thus the new will start out with the same value and properties as the old, but if it is setq'ed or putprop'ed, the value or property of the old will not be changed. If the second argument is nil, the new symbol has no value and no properties (except possibly internal system properties.) gensym LSUBR 0 or 1 args gensym creates and returns a new atomic symbol, which is not interned on an obarray (and therefore is not recognized by read.) The atomic symbol's pname is of the form prefix number, e.g. g0001. The number is incremented each time. If gensym is given an argument, a numeric argument is used to set the number. The pname of an atomic-symbol argument is used to set the prefix. For example: if (gensym) => g0007 then (gensym 'foo) => f0008 (gensym 40) => f0032 and (gensym) => f0033 Note that the number is in decimal and always four digits, and the prefix is always one character.  file: LISP, node: Defining Atomic Symbols as Functions, previous: Interning of Symbols, up: Atomic Symbols, next: Numbers, Source: MACLISP Manual 3/6/76 Atomic symbols may be used as names for functions. This is done by putting the actual function (a subr-object or a lambda-expression) on the property list of the atomic symbol as a "functional property," i.e. under one of the indicators expr, fexpr, macro, subr, lsubr, or fsubr. Array properties (see page 2-85) are also considered to be functional properties, so an atomic symbol which is the name of an array is also the name of a function, the accessing function of that array. When an atomic symbol which is the name of a function is applied, the function which it names is substituted. defun FSUBR defun is used for defining functions. The general form is: (defun name type (lambda-variable...) body...) However, name and type may be interchanged. type, which is optional, may be expr, fexpr, or macro. If it is omitted, expr is assumed. Examples: (defun addone (x) (1+ x)) ;defines an expr (defun quot fexpr (x) (car x)) ;defines a fexpr (defun fexpr quot (x) (car x)) ;is the same (defun zzz expr x ;this is how you (foo (arg 1)(arg 2))) ; define a lexpr. The first example above is really just defining a synonym. Another way to do this is: (defprop addone 1+ expr) That is, an atomic functional property indicates synonyming. This can be particularly useful to define a macro by an expr or fexpr, or even by a subr. The functions defprop and putprop may also be used for defining functions. There is a feature by which, when a file of functions has been compiled and loaded into the lisp environment, the file may be edited and then only those functions which were changed may be loaded for interpretive execution. This is done by compiling with the "E" switch, and then reading in the source file with the variable defun bound non-nil. Each function will have an expr-hash property maintained, which contains the sxhash of the interpreted definition of the function. defun will only redefine the function if this hash-code has changed. This feature is rather dangerous since reasonable alterations to the function definition may not change the sxhash and consequently may not take effect. Because of its general losingness, this feature is only available in the pdp-10 implementation and sometimes not even there. defun could have been defined by: (defun defun fexpr (x) ;circular, but you get the idea (prog (name type body) ; first, analyze the form, get arguments. (cond ((memq (car x) '(expr fexpr macro)) (setq type (car x) name (cadr x) body (cddr x))) ((memq (cadr x) '(expr fexpr macro)) (setq name (car x) type (cadr x) body (cddr x))) ((setq name (car x) type 'expr body (cdr x)))) (setq body (cons 'lambda body)) ; now, check for expr-hash hair. (cond ((and defun (get name 'expr-hash) (= (get name 'expr-hash) (sxhash body))) ) ; actually make the definition. ((putprop name body type))) (return name))) args LSUBR 1 or 2 args (args f) tells you the number of arguments expected by the function f. If f wants n arguments, args returns (nil . n). If f can take from m to n arguments, args returns (m . n). If f is an fsubr or a lexpr, expr, or fexpr, the results are meaningless. (args f x), where x is (nil . n) or (m . n), sets the number of arguments desired by the function f. This only works for compiled, non-system functions. sysp SUBR 1 arg The sysp predicate takes an atomic symbol as an argument. If the atomic symbol is the name of a system function (and has not been redefined), sysp returns the type of function (subr, lsubr, or fsubr). Otherwise sysp returns nil. Examples: (sysp 'foo) => nil (presumably) (sysp 'car) => subr (sysp 'cond) => fsubr  file: LISP, node: Numbers, previous: Defining Atomic Symbols as Functions, up: Function Descriptions, next: Number Predicates, Source: MACLISP Manual 3/6/76 * MENU: * Number Predicates:: * Comparison:: * Conversion:: * Arithmetic:: * Exponentiation and Logarithm Functions:: * Trigonometric Functions:: * Random Functions:: * Logical Operations on Numbers:: For a description of the various types of numbers used in Maclisp, see part 1.2.  file: LISP, node: Number Predicates, previous: Numbers, up: Numbers, next: Comparison, Source: MACLISP Manual 3/6/76 zerop SUBR 1 arg The zerop predicate returns t if its argument is fixnum zero or flonum zero. (There is no bignum zero.) Otherwise it returns nil. It is an error if the argument is not a number. If that is possible signp should be used. plusp SUBR 1 arg The plusp predicate returns t if its argument is strictly greater than zero, nil if it is zero or negative. It is an error if the argument is not a number. minusp SUBR 1 arg The minusp predicate returns t if its argument is a negative number, nil if it is a non-negative number. It is an error if the argument is not a number. oddp SUBR 1 arg The oddp predicate returns t if its argument is an odd number, otherwise nil. The argument must be a fixnum or a bignum. signp FSUBR The signp predicate is used to test the sign of a number. (signp c x) returns t if x's sign satisfies the test c, nil if it does not. x is evaluated but c is not. The result is always nil if x is not a number. c can be one of the following: l means x<0 le " x<_0 e " x=0 n " x=/0 ge " x>_0 g " x>0 Examples: (signp le -1) => t (signp n 0) => nil (signp g '(foo . bar)) => nil haulong SUBR 1 arg (haulong x) returns the number of significant bits in x. x can be a fixnum or a bignum. The result is the least integer not less than the base-2 logarithm of |x|+1. Examples: (haulong 0) => 0 (haulong 3) => 2 (haulong -7) => 3 (haulong 12345671234567) => 40.  file: LISP, node: Comparison, previous: Comparison, up: Numbers, next: Conversion, Source: MACLISP Manual 3/6/76 = SUBR 2 args (= x y) is t if x and y are numerically equal. x and y must be both fixnums or both flonums. Use equal to compare bignums. greaterp LSUBR 2 or more args greaterp compares its arguments, which must be numbers, from left to right. If any argument is not greater than the next, greaterp returns nil. But if the arguments to greaterp are strictly decreasing, the result is t. Examples: (greaterp 4 3) => t (greaterp 1 1) => nil (greaterp 4.0 3.6 -2) => t (greaterp 4 3 1 2 0) => nil > SUBR 2 args (> x y) is t if x is strictly greater than y, and nil otherwise. x and y must be both fixnums or both flonums. lessp LSUBR 2 or more args lessp compares its arguments, which must be numbers, from left to right. If any argument is not less than the next, lessp returns nil. But if the arguments to lessp are strictly increasing, the result is t. Examples: (lessp 3 4) => t (lessp 1 1) => nil (lessp -2 3.6 4) => t (lessp 0 2 1 3 4) => nil < SUBR 2 args (< x y) is t if x is strictly less than y, and nil otherwise. x and y must be both fixnums or both flonums. max LSUBR 1 or more args max returns the largest of its arguments, which must be numbers. If any argument is a flonum, the result will be a flonum. Otherwise, it will be a fixnum or a bignum depending on its magnitude. min LSUBR 1 or more args min returns the smallest of its arguments, which must be numbers. If any argument is a flonum, the result will be a flonum. Otherwise, it will be a fixnum or a bignum depending on its magnitude.  file: LISP, node: Conversion, previous: Comparison, up: Numbers, next: Arithmetic, Source: MACLISP Manual 3/6/76 fix SUBR 1 arg (fix x) converts x to a fixnum or a bignum depending on its magnitude. Examples: (fix 7.3) => 7 (fix -1.2) => -2 (fix 104) => 104 float SUBR 1 arg (float x) converts x to a flonum. Example: (float 4) => 4.0 (float 3.27) => 3.27 abs SUBR 1 arg (abs x) => |x|, the absolute value of the number x. abs could have been defined by: (defun abs (x) (cond ((minusp x) (minus x)) (t x) )) minus SUBR 1 arg minus returns the negative of its argument, which can be any kind of number. Examples: (minus 1) => -1 (minus -3.6) => 3.6 haipart SUBR 2 args (haipart x n) extracts n leading or trailing bits from the internal representation of x. x may be a fixnum or a bignum. n must be a fixnum. The value is returned as a fixnum or a bignum. If n is positive, the result contains the n high-order significant bits of |x|. If n is negative, the result contains the |n| low-order bits of |x|. If |n| is bigger than the number of significant bits in x, |x| is returned. Examples: (haipart 34567 7) => 162 (haipart 34567 -5) => 27 (haipart -34567 -5) => 27  file: LISP, node: Arithmetic, previous: Conversion, up: Numbers, next: Exponentiation and Logarithm Functions, Source: MACLISP Manual 3/6/76 General Arithmetic These functions will perform arithmetic on any kind of numbers, and always yield an exact result, except when used with flonums. (Flonums have limited precision and range.) Conversions to flonum or bignum representation are done as needed. Flonum representation will be used if any of the arguments are flonums; otherwise fixnum representation will be used if the result can fit in fixnum form, or bignum representation if it cannot. The two sections after this one describe other arithmetic functions which are more efficient but less powerful. plus LSUBR 0 or more args plus returns the sum of its arguments, which may be any kind of numbers. difference LSUBR 1 or more args difference returns its first argument minus the rest of its arguments. It works for any kind of numbers. times LSUBR 0 or more args times returns the product of its arguments. It works for any kind of numbers. quotient LSUBR 1 or more args quotient returns its first argument divided by the rest of its arguments. The arguments may any kind of number. Examples: (quotient 3 2) => 1 ;fixnum division truncates. (quotient 3 2.0) => 1.5 ;but flonum division does not.. add1 SUBR 1 arg (add1 x) => x+1. x may be any kind of number. sub1 SUBR 1 arg (sub1 x) => x-1. x may be any kind of number. remainder SUBR 2 args (remainder x y) => the remainder of the division of x by y. The sign of the remainder is the same as the sign of the dividend. The arguments must be fixnums or bignums. gcd SUBR 2 args (gcd x y) => the greatest common divisor of x and y. The arguments must be fixnums or bignums. expt SUBR 2 args z (expt x z) = x The exponent z may be a bignum if the base x is 0, 1, or -1; otherwise z should be a fixnum. x may be any kind of number. As a special feature, expt allows its second argument to be a flonum, in which case the first argument is converted to a flonum and the exponentiation is performed in floating point, using logarithms. The result is a flonum in this case. .bp Fixnum Arithmetic Source: MACLISP Manual 3/6/76 These functions require their arguments to be fixnums and produce only fixnum results. If the true result, which would be returned by the more general functions described previously, is too large to be represented as a fixnum, the result actually returned will be truncated to an implementation-dependent number of bits, which is 36. (including the sign) in the Multics and pdp-10 implementations. The compiler produces highly-optimized code for these operations. + LSUBR 0 or more args + returns the sum of its arguments. The arguments must be fixnums, and the result is always a fixnum. Examples: (+ 2 6 -1) => 7 (+ 3) => 3 ;trivial case (+) => 0 ;identity element - LSUBR 0 or more args This is the fixnum-only subtraction function. With one argument, it returns the number's negation. With more than one argument, it returns the first argument minus the rest of the arguments. (-) => 0, the identity element (- 3) => -3 (- 5 3) => 2 (- 2 6 -1) => -3 etc. * LSUBR 0 or more args * returns the product of its arguments. Examples: (* 4 5 -6) => -120. (* 3) => 3 ;trivial case (*) => 1 ;identity element / LSUBR 0 or more args This is the fixnum-only division function. The arguments must be fixnums and the result of the division is truncated to an integer and returned as a fixnum. Note that the name of this function must be typed in as //, since Lisp uses / as an escape character. If used with more than one argument, it divides the first argument by the rest of the arguments. If used with only one argument, it returns the fixnum reciprocal of that number, which is -1, 0, 1, or undefined depending on whether the number is -1, large, 1, or 0. (//) => 1, the identity element. (// 20. 5) => 4 (// 100. 3 2) => 16. etc. 1+ SUBR 1 arg (1+ x) => x+1. x must be a fixnum. The result is always a fixnum. 1- SUBR 1 arg (1- x) => x-1. x must be a fixnum. The result is always a fixnum. \ SUBR 2 args (\ x y) returns the remainder of x divided by y, with the sign of x. x and y must be fixnums. Examples: (\ 5 2) => 1 (\ 65. -9.) => 2 (\ -65. 9.) => -2 \\ SUBR 2 args This subr of two arguments is like gcd, but only accepts fixnums. This makes it faster than gcd. ^ SUBR 2 args ^ is the fixnum only exponentiation function. It is somewhat faster than expt, but requires its arguments to be fixnums, uses fixnum arithmetic, and always returns a fixnum result, which will be incorrect if the true result is too large to be represented as a fixnum. .bp Flonum Arithmetic Source: MACLISP Manual 3/6/76 These functions require their arguments to be flonums, and always produce flonum results. If the true result is too large or too small to be represented as a flonum, an arithmetic underflow or overflow error will occur. (In the pdp- 10 implementation these errors are not detected in compiled programs.) The compiler produces highly-optimized code for these operations. +$ LSUBR 0 or more args +$ returns the sum of its arguments. Examples: (+$ 4.1 3.14) => 7.24 (+$ 2.0 1.5 -3.6) => -0.1 (+$ 2.6) => 2.6 ;trivial case (+$) => 0.0 ;identity element -$ LSUBR 0 or more args This is the flonum-only subtraction function. When used with only one argument, it returns the number's negation. Otherwise, it returns the first argument minus the rest of the arguments. (-$) => 0.0, the identity element (-$ x) => the negation of x. (-$ 6.0 2.5) => 4.5 (-$ 2.0 1.5 -3.6) => 3.1 etc. *$ LSUBR 0 or more args *$ returns the product of its arguments. Examples: (*$ 3.0 2.0 4.0) => 24.0 (*$ 6.1) => 6.1 ;trivial case (*$) => 1.0 ;identity element /$ LSUBR 0 or more args This is the flonum-only division function. Note that the name of this function must be typed in as //$, since Lisp uses / as an escape character. This function computes the reciprocal if given only one argument. If given more than one argument, it divides the first by the rest. (//$) => 1.0, the identity element (//$ 5.0) => 0.2 (//$ 6.28 3.14) => 2.0 (//$ 100.0 3.0 2.0) => 16.5 etc. 1+$ SUBR 1 arg (1+$ x) => x+1.0. x must be a flonum. The result is always a flonum. 1-$ SUBR 1 arg (1-$ x) => x-1.0. x must be a flonum. The result is always a flonum. ^$ SUBR 2 args ^$ is the flonum-only exponentiation function. The first argument must be a flonum, the second must be a fixnum (repeat, a fixnum), and the result is a flonum. To raise a flonum to a flonum power, use (expt x y) or (exp (*$ y (log x))).  file: LISP, node: Exponentiation and Logarithm Functions, previous: Arithmetic, up: Numbers, next: Trigonometric Functions, Source: MACLISP Manual 3/6/76 sqrt SUBR 1 arg (sqrt x) => a flonum which is the square root of the number x. This is more accurate than (expt x 0.5). The following code, which is due to Gosper, should be written if the square root of a bignum is desired. It is essentially a Newton iteration, with appropriate precautions for integer truncation. (defun bsqrt (n) (bsqrt1 (abs n) (expt 2 (// (1+ (haulong n)) 2)))) (defun bsqrt1 (n guess) ((lambda (next) (cond ((lessp next guess) (bsqrt1 n next)) (t guess))) (quotient (plus guess (quotient n guess)) 2))) exp SUBR 1 arg x (exp x) => e log SUBR 1 arg (log x) => the natural logarithm of x.  file: LISP, node: Trigonometric Functions, previous: Exponentiation and Logarithm Functions, up: Numbers, next: Random Functions, Source: MACLISP Manual 3/6/76 sin SUBR 1 arg (sin x) gives the trigonometric sine of x. x is in radians. x may be a fixnum or a flonum. cos SUBR 1 arg (cos x) returns the cosine of x. x is in radians. x may be a fixnum or a flonum. atan SUBR 2 args (atan x y) returns the arctangent of x/y, in radians. x and y may be fixnums or flonums. y may be 0 as long as x is not also 0.  file: LISP, node: Random Functions, previous: Trigonometric Functions, up: Numbers, next: Logical Operations on Numbers, Source: MACLISP Manual 3/6/76 random LSUBR 0 to 2 args (random) returns a random fixnum. (random nil) restarts the random sequence at its beginning. (random x), where x is a fixnum, returns a random fixnum between 0 and x-1 inclusive. A useful function is: (defun frandom () (//$ (float (random 10000.)) 10000.0))) which returns a random flonum between 0.0 and 1.0. (SSTATUS RANDOM n) sets the random number seed from the integer n. Note also (STATUS RANDOM) returns the complete state of the random number generator, not just the seed. This saved state can later be restored by doing (SSTATUS RANDOM savedstate). zunderflow SWITCH If an intermediate or final flonum result in the interpretive arithmetic functions (times, *$, expt, etc.) is too small in magnitude to be represented by the machine, corrective action will be taken according to the zunderflow switch. If the value of zunderflow is non-nil, the offending result will be set to 0.0 and computation will proceed. If the value of zunderflow is nil, an error will be signalled. nil is the initial value. In the pdp-10 implementation compiled code is not affected by zunderflow if the arithmetic in question was open-coded by the compiler. Instead, computation proceeds using a result with a binary exponent 256 higher than the correct exponent. In the Multics implementation zunderflow works the same for compiled code as for interpreted code. See (sstatus divov), which controls division by zero (part 3.7).  file: LISP, node: Logical Operations on Numbers, previous: Random Functions, up: Numbers, next: Character Manipulation, Source: MACLISP Manual 3/6/76 These functions may be used freely for bit manipulation; the compiler recognizes them and produces efficient code. boole LSUBR 3 or more args (boole k x y) computes a bit by bit Boolean function of the fixnums x and y under the control of k. k must be a fixnum between 0 and 17 (octal). If the binary representation of k is abcd, then the truth table for the Boolean operation is: y ___|_0__1_ 0| a c x | 1| b d If boole has more than three arguments, it goes from left to right; thus (boole k x y z) = (boole k (boole k x y) z) The most common values for k are 1 (and), 7 (or), 6 (xor). You can get the complement, or logical negation, of x by (boole 6 x -1). The following macros are often convenient: (defun logand macro (x) (subst (cdr x) 'f '(boole 1 . f))) (defun logor macro (x) (subst (cdr x) 'f '(boole 7 . f))) (defun logxor macro (x) (subst (cdr x) 'f '(boole 6 . f))) Alternatively, these could be defined with macrodef (see part 6.2): (macrodef logand x (boole 1 . x)) (macrodef logor x (boole 7 . x)) (macrodef logxor x (boole 6 . x)) lsh SUBR 2 args (lsh x y), where x and y are fixnums, returns x shifted left y bits if y is positive, or x shifted right |y| bits if y is negative. Zero-bits are shifted in to fill unused positions. The result is undefined if |y| > 36. The number 36 is implementation dependent, but this is the number used in both the Multics and pdp-10 implementations. Examples: (lsh 4 1) => 10 (octal) (lsh 14 -2) => 3 (lsh -1 1) => -2 rot SUBR 2 args (rot x y) returns as a fixnum the 36-bit representation of x, rotated left y bits if y is positive, or rotated right |y| bits if y is negative. x and y must be fixnums. The results are undefined if |y| > 36. As with lsh, the number 36 depends on the implementation. Examples: (rot 1 2) => 4 (rot -1 7) => -1 (rot 601234 36.) => 601234 (rot 1 -2) => 200000000000 (rot -6 6) => -501 The following feature only exists in the pdp-10 implementation. The internal representation of flonums may be hacked using these functions. lsh or rot applied to a flonum operates on the internal representation of the flonum and returns a fixnum result. For example, (lsh 0.5 0) => 200400000000 (octal). The following function also exists: fsc SUBR 2 args (fsc x y) performs a FSC instruction on the two numbers x and y, and returns the result as a flonum. Consult the pdp-10 processor manual if you want to use this. x and y may be fixnums or flonums; fsc just uses the machine representations of the numbers. If y is greater than 777777 octal, the FSC instruction is omitted and the possibly-unnormalized flonum with the same machine representation as x is returned.  file: LISP, node: Character Manipulation, previous: Logical Operations on Numbers, up: Function Descriptions, next: Arrays, Source: MACLISP Manual 3/6/76 Character Objects Character Strings 7.1 Character Objects An atomic symbol with a one-character pname is often called a character object and used to represent the ascii character which is its pname. In addition the atomic symbol with a zero-length pname represents the ascii null character. Functions which take a character object as an argument usually also accept a string one character long or a fixnum equal to the ascii-code value for the character. Character objects are always interned on the obarray (see page 2-54), so they may be compared with the function eq. ascii SUBR 1 arg (ascii x), where x is a number, returns the character object for the ascii code x. Examples: (ascii 101) => A (ascii 56) => /. getchar SUBR 2 args (getchar x n), where x is an atomic symbol and n is a fixnum, returns the n'th character of x's pname; n = 1 selects the leftmost character. The character is returned as a character object. nil is returned if n is out of bounds. getcharn SUBR 2 args getcharn is the same as getchar except that the character is returned as a fixnum instead of a character object. maknam SUBR 1 arg maknam takes as its argument a list of characters and returns an uninterned atomic symbol whose pname is constructed from the list of characters. The characters may be represented either as fixnums (ascii codes) or as character objects. Example: (maknam '(a b 60 d)) => ab0d implode SUBR 1 arg implode is the same as maknam except that the resulting atomic symbol is interned. It is more efficient than doing (intern (maknam x)), although it is less efficient than plain maknam which should be used when interning is not required. readlist SUBR 1 arg The argument to readlist is a list of characters. The characters may be represented either as fixnums (ascii codes) or as character objects. The characters in the list are assembled into an S-expression as if they had been typed into read (see part 5.1.) If macro characters are used, any usage in the macro character function of read, readch, tyi, or tyipeek not explicitly specifying an input file takes input from readlists's argument rather than from an I/O device or a file. This causes macro characters to work as you would expect. Examples: (readlist '(a b c)) => abc (readlist '( /( p r 151 n t / /' f o o /) )) => (print (quote foo)) ;ascii 151 = "i" Note the use of the slashified special characters left parenthesis, space, quote, right parenthesis in the argument to readlist. explode SUBR 1 arg (explode x) returns a list of characters, which are the characters that would be typed out if (prin1 x) were done, including slashes for special characters but not including extra newlines inserted to prevent characters from running off the right margin. Each character is represented by a character object. Example: (explode '(+ /12 3)) => ( /( + / // /1 /2 / /3 /) ) ;Note the presence of slashified spaces in this list. explodec SUBR 1 arg (explodec x) returns a list of characters which are the characters that would be typed out if (princ x) were done, not including extra newlines inserted to prevent characters from running off the right margin. Special characters are not slashified. Each character is represented by a character object. Example: (explodec '(+ /12 3)) => ( /( + / /1 /2 / /3 /) ) exploden SUBR 1 arg (exploden x) returns a list of characters which are the characters that would be typed out if (princ x) were done, not including extra newlines inserted to prevent characters from running off the right margin. Special characters are not slashified. Each character is represented by a number which is the ascii code for that character. cf. explodec. Example: (exploden '(+ /12 3)) => (50 53 40 61 62 40 63 51) flatsize SUBR 1 arg (flatsize x) returns the number of characters prin1 would use to print x out. flatc SUBR 1 arg (flatc x) returns the number of characters princ would use to print x out, without slashifying special characters. .bp 7.2 Character Strings Source: MACLISP Manual 3/6/76 These character string functions only exist at present in the Multics implementation of Maclisp. A predicate to test if your implementation has these functions is (status feature strings) These functions all accept atomic symbols in place of strings as arguments; in this case the pname of the atomic symbol is used as the string. When the value of one of these functions is described as a string, it is always a string and never an atomic symbol. Also see the functions on page 2-52. catenate LSUBR 0 or more args The arguments are character strings. The result is a string which is all the arguments concatenated together. Example: (catenate "foo" "-" "bar") => "foo-bar" index SUBR 2 args index is like the PL/I builtin function index. The arguments are character strings. The position of the first occurrence of the second argument in the first is returned, or 0 if there is none. Examples: (index "foobar" "ba") => 4 (index "foobar" "baz") => 0 (index "goobababa" "bab") => 4 stringlength SUBR 1 arg The argument to stringlength must be a character string. The number of characters in it is returned. Examples: (stringlength "foo") => 3 (stringlength "") => 0 substr LSUBR 2 or 3 args This is like the PL/I substr builtin. (substr x m n) returns a string n characters long, which is a portion of the string x beginning with its m'th character and proceeding for n characters. m and n must be fixnums, x must be a string. (substr x m) returns the portion of the string x beginning with its m'th character and continuing until the end of the string. Examples: (substr "foobar" 3 2) => "ob" (substr "resultmunger" 6) => "tmunger" get_pname SUBR 1 arg (get_pname x) returns the pname of x as a character string. x must be an atomic symbol. make_atom SUBR 1 arg make_atom returns an atomic symbol, uninterned, whose pname is given as a character string argument. Example: (make_atom "foo") => foo ;which is not eq to a ;foo that is read in.  file: LISP, node: Arrays, previous: Character Manipulation, up: Function Descriptions, next: Mapping Functions, Source: MACLISP Manual 3/6/76 As explained in part 1.2, an array is a group of cells which may contain Lisp objects. The individual cells are selected by numerical subscripts. An array is designated by a special atomic object called an array-pointer. Array-pointers can be returned by the array-creation functions array and *array. An array-pointer may either be used directly to refer to the array, or, for convenience in referring to the array through input/output media, it may be placed on the property list of an atomic symbol under the indicator array, and then that symbol can be used as the name of the array. There are several types of arrays. The main types are ordinary arrays, whose cells can hold any type of object, and number arrays, whose cells can only hold numbers. Number arrays permit more efficient code to be compiled for numerical applications, and take less space than an ordinary array which contains the same number of numbers. See the array* declaration (part 4.2) and the arraycall function (page 2-12). When an array is created its type must be declared by giving a "type code." The type code for ordinary arrays is t. For number arrays, the type code is either fixnum or flonum. A particular number array can only hold one type of numbers because its cells contain the machine representation of the number, not the Lisp-object representation. Some other types of arrays are: un-garbage-collected arrays, with a type- code of nil, which are the same as ordinary arrays except that they are not protected by the garbage collector and therefore can be used for certain esoteric hacks; obarrays, with a type-code of obarray, which are used to maintain tables of known atomic symbols so that the same atomic symbol will be referenced when the same pname is typed in; and readtables, with a type-code of readtable, which are used to remember the syntax specifications for the Lisp input reader. Normally, there is only one readtable and one obarray, supplied by the system, but the user may create additional readtables and obarrays in order to provide special non-Lisp environments or to gain additional control over the Lisp environment. Lisp functions such as read can be made to use an additional readtable or obarray by re-binding the variable readtable or obarray, respectively. An array-pointer may also be dead, in which case it does not point to any array. One of the functions array, *array, or *rearray may be used to revivify a dead array-pointer. The functions array and *array are used to create arrays. The first argument may be an atomic symbol, which makes that atomic symbol the name of an array, putting an array-pointer on its property list, or redefining an array-pointer that was already on the property list to point to the new array. Alternatively the first argument may be an array pointer, which causes that array pointer to be redefined to point to a new array, or it may be nil, which causes a new array pointer to be created and returned. Except in the latter case, array returns its first argument. *array always returns the array pointer, never the atomic symbol. A readtable or an obarray may not be created with user-specified dimensions. The dimensions are always determined by Lisp. Other types of arrays allow any reasonable number (at least 3, anyway) of dimensions to be specified when they are created. The subscripts range from 0 up to 1 less than the dimension specified. Ordinary and un-garbage-collected arrays are initialized to nil. Fixnum arrays are initialized to 0. Flonum arrays are initialized to 0.0. Obarrays are initialized according to the third argument given to array or *array. nil causes a completely empty obarray to be created. Not even nil will be interned on this obarray. t causes the current obarray (value of the symbol obarray) to be copied. An array-pointer which is an obarray, or an atomic symbol which names an obarray, causes that obarray to be copied. If no third argument is given, the current obarray is copied. Readtables are initialized in a similar fashion. If the third argument of array or *array is nil, then the current readtable is copied. If it is t, then the readtable being created is initialized to the initial standard Lisp readtable, including the macro characters ' and ;. (Note that this is the opposite of the t-nil convention for obarrays. This is for compatibility with the makreadtable function, which no longer exists.) An array-pointer or symbol of a readtable to be copied may also be given. If no third argument is given, the current readtable is copied. An array-pointer may be redefined to an entirely different type and size of array, using the *array function. It remains the same array-pointer, eq to itself. If a variable was setq'ed to the array-pointer, that variable will now indicate the new array. If a symbol has that array-pointer on its property list, it will now be the name of the new array. The *rearray function can be used to redefine the size or arrangement of dimensions of an array without losing its contents, or to make an array-pointer not point to any array (become dead). If there is only one argument, the array- pointer is killed, the array's contents are discarded, and the array-pointer becomes a "dead array" as described above. *array may now be used to redefine it as a new array. If more than one argument is given to *rearray, they are the same arguments as to *array. *rearray with more than one argument cannot be used to change the type of an array, and cannot operate on a readtable or an obarray, but it can be used to change the dimensions of an array. The modified array will be initialized from its old contents rather than nil, 0, or 0.0. The elements are taken in row-major order for initialization purposes, and if there are not enough, nil, 0, or 0.0 will be used to fill the remaining elements of the modified array, according to the type. The Multics implementation also has a type of arrays called external arrays. External arrays reside in a Multics segment rather than within the Lisp environment. They behave much like fixnum arrays, and should be declared as such to the compiler. To create an external array, use a form such as (array foo external pointer length) The pointer is a packed pointer to the beginning of the array, i.e. a fixnum whose first six octal digits are the segment number and whose second six octal digits are the word address. The length is the number of words in the array. External arrays can only have one dimension, can only contain fixnums, and are not initialized when they are created. They cannot usefully be saved by the save function. This type of array can be used for communication between Lisp programs and Multics programs or subsystems written in other languages, when large amounts of numerical data or machine words must be passed back and forth. See also defpl1 (part 4.6). If you want the range of subscripts on arrays to be checked, it is necessary to set the *rset flag non-nil (i.e. run in (*rset t) mode) and to avoid the use of in-line array accessing (i.e. the array* declaration) in compiled programs. The amount of checking performed when *rset is nil and/or compiled code is used depends on the implementation. Here is an example of a use of arrays: (defun matrix-multiply (arr1 arr2 result) (and (eq (typep arr1) 'symbol) ;convert arguments (setq arr1 (get arr1 'array))) ;to array-pointers (and (eq (typep arr2) 'symbol) (setq arr2 (get arr2 'array))) (and (eq (typep result) 'symbol) (setq result (get result 'array))) (do ((ii (cadr (arraydims result))) ;get relevant (jj (caddr (arraydims result))) ;dimensions (kk (cadr (arraydims arr2)))) () (do i 0 (1+ i) (= i ii) ;result := arr1 x arr2 (do j 0 (1+ j) (= j jj) (do ((k 0 (1+ k)) (r 0.0)) ((= k kk) (store (arraycall flonum result i j) r)) (setq r (+$ r (*$ (arraycall flonum arr1 i k) (arraycall flonum arr2 k j) ))))))) result) *array LSUBR 3 or more args (*array x y b1 b2 ... bn) defines x to be an n-dimensional array. The first subscript may range from 0 to b1 minus 1, the second from 0 to b2 minus 1, etc. y is the type of array, as explained above. It may be chosen from among: t, nil, fixnum, flonum, readtable, obarray. array FSUBR (array x y b1 b2 ... bn) has the same effect as (*array (quote x) (quote y) b1 b2 ... bn). This special form is provided for your typing convenience. *rearray LSUBR 1 or more args *rearray is used to redefine the dimensions of an array. (*rearray x) kills the array-pointer x, or the array-pointer which is the array property of the atomic symbol x. The storage used by the associated array is reclaimed. The value returned is t if x was an array, nil if it was not. (*rearray x type dim1 dim2 ... dimn) is like (*array x type dim1 dim2 ... dimn) except that the contents of the previously existing array named x are copied into the new array named x. If it is a multi-dimensional array, row-major order is used. This means the last subscript varies the most rapidly as the array is traversed. store FSUBR The special form (store array-ref value) is used to store an object into a particular cell of an array. The first element of the form, array-ref, must be a subscripted reference to an array, or an invocation of arraycall. By coincidence, certain other forms work as array-ref, for instance (apply f l) where f turns out to be an array. The second element, value, is evaluated and stored into the specified cell of the array. store evaluates its second "argument" before its first "argument". Examples: (store (data i j) (plus i j)) (store (sine-values (fix (*$ x 100.0))) (sin x)) (store (arraycall fixnum az i j) 43) arraydims SUBR 1 arg (arraydims x), where x is an array-pointer or an atomic symbol with an array property, returns a list of the type and bounds of the array. Thus if A was defined by (array A t 10 20), fillarray SUBR 2 args (fillarray a l) fills the array a with consecutive items from the list l. If the array is too short to contain all the items in the list, the extra items are ignored. If the list is too short to fill up the array, the last element of the list is used to fill each of the remaining cells in the array. (fillarray x y) fills the array x from the contents of the array y. If y is bigger than x, the extra elements are ignored. If y is smaller than x, the rest of x is unchanged. x and y must be atomic symbols which have array properties, or array-pointers. The two arrays must be of the same type, and they may not be readtables or obarrays. The list-into-array case of fillarray could have been defined by: (defun fillarray (a x) (do ((x x (or (cdr x) x)) (n 0 (1+ n)) (hbound (cadr (arraydims a)))) ((= n hbound)) (store (a n) (car x)) ) a) An extension to the above definition is that fillarray will work with arrays of more than one dimension, filling the array in row-major order. fillarray returns its first argument. listarray LSUBR 1 or 2 args (listarray array-name) takes the elements of the array specified by array- name and returns them as the elements of a list. The length of the list is the size of the array and the elements are present in the list in the same order as they are stored in the array, starting with the zero'th element. If the array has more than one dimension row-major order is used. (listarray array-name n) is the same, except that at most the first n elements will be listed. array-name may be an array-pointer or an atomic symbol with an array- Number arrays may be efficiently saved in the file system and restored by using the functions loadarrays and dumparrays. loadarrays SUBR 1 arg (loadarrays file-spec) reloads the arrays in the file, and returns a list of 3-lists, of the form: ( (newname oldname size) ...) newname is a gensym'ed atom, which is the name of the reloaded array. (newname ought to be an array-pointer, but this function was defined before array-pointers were invented.) oldname is the name the array had when it was dumped. size is the number of elements in the array. dumparrays SUBR 2 args (dumparrays (array1 array2 ...) file-spec) dumps the listed arrays into the specified file. The arrays must be fixnum or flonum arrays. In both of the above, the file-spec argument is dependent on the system. In ITS or DEC-10 Lisp, the file-spec is a list of zero to four items, as in uread, and the same defaults apply. In Multics Lisp, the file-spec is an atomic symbol or a string which gives the pathname of the segment to be used. The defaults and other features of the Lisp I/O system are not applied. Only a segment may be specified, not a stream. As a special compatibility feature, in Multics Lisp loadarrays will recognize a pdp-10 dumparrays file. (One can be moved to Multics through the ARPA Network File Transfer Protocol if the "type image" and "bytesize 36" commands are employed.) The pnames will be converted to lower case and flonums will be converted to the H6880 machine representation. dumparrays can create a file which pdp-10 loadarrays can read, including upper-case pnames and pdp-10 format flonums, if it is invoked as follows: (dumparrays (array1 array2...) '(pdp10 file-spec))  file: LISP, node: Mapping Functions, previous: Arrays, up: Function Descriptions, Source: MACLISP Manual 3/6/76 Mapping is a type of iteration in which a function is successively applied to pieces of a list. There are several options for the way in which the pieces of the list are chosen and for what is done with the results returned by the applications of the function. For example, mapcar operates on successive elements of the list. As it goes down the list, it calls the function giving it an element of the list as its one argument: first the car, then the cadr, then the caddr, etc., continuing until the end of the list is reached. The value returned by mapcar is a list of the results of the successive calls to the function. An example of the use of mapcar would be mapcar'ing the function abs over the list (1 -2 -4.5 6.0e15 -4.2). The result is (1 2 4.5 6.0e15 4.2). The form of a call to mapcar is (mapcar f x) where f is the function to be mapped and x is the list over which it is to be mapped. Thus the example given above would be written as (mapcar 'abs '(1 -2 -4.5 6.0e15 -4.2)) This has been generalized to allow a form such as (mapcar f x1 x2 ... xn) In this case f must be a function of n arguments. mapcar will proceed down the lists x1, x2, ..., xn in parallel. The first argument to f will come from x1, the second from x2, etc. The iteration stops as soon as any of the lists is exhausted. There are five other mapping functions besides mapcar. maplist is like mapcar except that the function is applied to the list and successive cdr's of that list rather than to successive elements of the list. map and mapc are like maplist and mapcar respectively except that the return value is the first list being mapped over and the results of the function are ignored. mapcan and mapcon are like mapcar and maplist respectively except that they combine the results of the function using nconc instead of list. That is, (defun mapcon (f x y) (apply 'nconc (maplist f x y))) Of course, this definition is far less general than the real one. Sometimes a do or a straight recursion is preferable to a map; however, the mapping functions should be used wherever they naturally apply because this increases the clarity of the code. Often f will be a lambda-type functional form rather than the atomic-symbol name of a function. For example, (mapcar '(lambda (x) (cons x something)) some-list) The functional argument to a mapping function must be acceptable to apply - it cannot be a macro. A fexpr or an fsubr may be acceptable however the results will be bizarre. For instance, mapping set works better than mapping setq, and mapping cond is unlikely to be useful. It is permissible (and often useful) to break out of a map by use of a go, return, or throw in a lambda-type function being mapped. This is a relaxation of the usual prohibition against "non-local" go's and return's. If go or return is used the program may have to be compiled with the (mapex t) declaration, depending on the implementation, so watch out! Consider this function which is similar to and, except that it works on a list, instead of on separate arguments. (defun andl (x) (catch (progn (mapc (function (lambda (y) (or y (throw nil the-answer)) )) x) t) the-answer)) Admittedly this could be better expressed as a do: (defun andl (x) (do ((y x (cdr y))) ((null y) t) (or (car y) (return nil)) )) Here is a table showing the relations between the six map functions. applies function to | successive | successive | | sublists | elements | ---------------+--------------+---------------+ its own | | | second | map | mapc | argument | | | ---------------+--------------+---------------+ list of the | | | returns function | maplist | mapcar | results | | | ---------------+--------------+---------------+ nconc of the | | | function | mapcon | mapcan | results | | | ---------------+--------------+---------------+ mapatoms LSUBR 1 or 2 args (mapatoms fn obarray) applies the function fn to all the symbols on the specified obarray. If the second argument is omitted, the current obarray is used. Note that the obarray argument must be an array-pointer, not a symbol which names an array. The symbol obarray is bound to the obarray being mapped over during the execution of mapatoms. This function exists because some of the cells in an obarray contain lists of symbols and others contain single symbols, and user programs shouldn't have to know this. Example: (mapatoms (function (lambda (x) (and (sysp x) (print (list x (sysp x) (args x))) ))))  file: LISP, node: Indices, up: Top, Source: MACLISP Manual 3/6/76 Function Index Atom Index Concept Index Function Index *. . . . . . . . . . . . . . 2-69 LSUBR 0 or more args *$ . . . . . . . . . . . . . 2-72 LSUBR 0 or more args *array . . . . . . . . . . . 2-90 LSUBR 3 or more args *function. . . . . . . . . . 2-6 FSUBR *rearray . . . . . . . . . . 2-90 LSUBR 1 or more args +. . . . . . . . . . . . . . 2-69 LSUBR 0 or more args +$ . . . . . . . . . . . . . 2-72 LSUBR 0 or more args -. . . . . . . . . . . . . . 2-69 LSUBR 0 or more args -$ . . . . . . . . . . . . . 2-72 LSUBR 0 or more args /. . . . . . . . . . . . . . 2-69 LSUBR 0 or more args /$ . . . . . . . . . . . . . 2-72 LSUBR 0 or more args 1+ . . . . . . . . . . . . . 2-70 SUBR 1 arg 1+$. . . . . . . . . . . . . 2-73 SUBR 1 arg 1- . . . . . . . . . . . . . 2-70 SUBR 1 arg 1-$. . . . . . . . . . . . . 2-73 SUBR 1 arg <. . . . . . . . . . . . . . 2-63 SUBR 2 args =. . . . . . . . . . . . . . 2-63 SUBR 2 args >. . . . . . . . . . . . . . 2-63 SUBR 2 args abs. . . . . . . . . . . . . 2-65 SUBR 1 arg add1 . . . . . . . . . . . . 2-68 SUBR 1 arg alphalessp . . . . . . . . . 2-52 SUBR 2 args and. . . . . . . . . . . . . 2-32 FSUBR append . . . . . . . . . . . 2-17 LSUBR 0 or more args apply. . . . . . . . . . . . 2-5 LSUBR 2 or 3 args arg. . . . . . . . . . . . . 2-10 SUBR 1 arg args . . . . . . . . . . . . 2-59 LSUBR 1 or 2 args array. . . . . . . . . . . . 2-90 FSUBR arraycall. . . . . . . . . . 2-12 FSUBR arraydims. . . . . . . . . . 2-91 SUBR 1 arg ascii. . . . . . . . . . . . 2-81 SUBR 1 arg assoc. . . . . . . . . . . . 2-26 SUBR 2 args assq . . . . . . . . . . . . 2-27 SUBR 2 args atan . . . . . . . . . . . . 2-75 SUBR 2 args atom . . . . . . . . . . . . 2-1 SUBR 1 arg bigp . . . . . . . . . . . . 2-1 SUBR 1 arg boole. . . . . . . . . . . . 2-77 LSUBR 3 or more args boundp . . . . . . . . . . . 2-46 SUBR 1 arg caaaar . . . . . . . . . . . 2-14 SUBR 1 arg caaadr . . . . . . . . . . . 2-14 SUBR 1 arg caadar . . . . . . . . . . . 2-14 SUBR 1 arg caaddr . . . . . . . . . . . 2-14 SUBR 1 arg caadr. . . . . . . . . . . . 2-14 SUBR 1 arg caar . . . . . . . . . . . . 2-14 SUBR 1 arg cadaar . . . . . . . . . . . 2-14 SUBR 1 arg cadadr . . . . . . . . . . . 2-14 SUBR 1 arg cadar. . . . . . . . . . . . 2-14 SUBR 1 arg caddar . . . . . . . . . . . 2-14 SUBR 1 arg cadddr . . . . . . . . . . . 2-14 SUBR 1 arg caddr. . . . . . . . . . . . 2-14 SUBR 1 arg cadr . . . . . . . . . . . . 2-14 SUBR 1 arg car. . . . . . . . . . . . . 2-13 SUBR 1 arg catch. . . . . . . . . . . . 2-40 FSUBR catenate . . . . . . . . . . 2-85 LSUBR 0 or more args cdaaar . . . . . . . . . . . 2-14 SUBR 1 arg cdaadr . . . . . . . . . . . 2-14 SUBR 1 arg cdaar. . . . . . . . . . . . 2-14 SUBR 1 arg cdadar . . . . . . . . . . . 2-14 SUBR 1 arg cdaddr . . . . . . . . . . . 2-14 SUBR 1 arg cdadr. . . . . . . . . . . . 2-14 SUBR 1 arg cdar . . . . . . . . . . . . 2-14 SUBR 1 arg cddaar . . . . . . . . . . . 2-14 SUBR 1 arg cddadr . . . . . . . . . . . 2-14 SUBR 1 arg cddar. . . . . . . . . . . . 2-14 SUBR 1 arg cdddar . . . . . . . . . . . 2-14 SUBR 1 arg cddddr . . . . . . . . . . . 2-14 SUBR 1 arg cdddr. . . . . . . . . . . . 2-14 SUBR 1 arg cddr . . . . . . . . . . . . 2-14 SUBR 1 arg cdr. . . . . . . . . . . . . 2-13 SUBR 1 arg comment. . . . . . . . . . . 2-8 FSUBR cond . . . . . . . . . . . . 2-32 FSUBR cons . . . . . . . . . . . . 2-14 SUBR 2 args copysymbol . . . . . . . . . 2-55 SUBR 2 args cos. . . . . . . . . . . . . 2-75 SUBR 1 arg defprop. . . . . . . . . . . 2-50 FSUBR defun. . . . . . . . . . . . 2-57 FSUBR delete . . . . . . . . . . . 2-24 LSUBR 2 or 3 args delq . . . . . . . . . . . . 2-25 LSUBR 2 or 3 args difference . . . . . . . . . 2-67 LSUBR 1 or more args dumparrays . . . . . . . . . 2-93 SUBR 2 args eq . . . . . . . . . . . . . 2-2 SUBR 2 args equal. . . . . . . . . . . . 2-3 SUBR 2 args err. . . . . . . . . . . . . 2-43 FSUBR error. . . . . . . . . . . . 2-42 LSUBR 0 to 3 args errset . . . . . . . . . . . 2-42 FSUBR eval . . . . . . . . . . . . 2-5 LSUBR 1 or 2 args exp. . . . . . . . . . . . . 2-74 SUBR 1 arg explode. . . . . . . . . . . 2-82 SUBR 1 arg explodec . . . . . . . . . . 2-83 SUBR 1 arg exploden . . . . . . . . . . 2-83 SUBR 1 arg expt . . . . . . . . . . . . 2-68 SUBR 2 args fillarray. . . . . . . . . . 2-92 SUBR 2 args fix. . . . . . . . . . . . . 2-65 SUBR 1 arg fixp . . . . . . . . . . . . 2-1 SUBR 1 arg flatc. . . . . . . . . . . . 2-83 SUBR 1 arg flatsize . . . . . . . . . . 2-83 SUBR 1 arg float. . . . . . . . . . . . 2-65 SUBR 1 arg floatp . . . . . . . . . . . 2-1 SUBR 1 arg fsc. . . . . . . . . . . . . 2-78 SUBR 2 args funcall. . . . . . . . . . . 2-11 LSUBR 1 or more args function . . . . . . . . . . 2-6 FSUBR gcd. . . . . . . . . . . . . 2-68 SUBR 2 args gensym . . . . . . . . . . . 2-55 LSUBR 0 or 1 args get. . . . . . . . . . . . . 2-49 SUBR 2 args getchar. . . . . . . . . . . 2-81 SUBR 2 args getcharn . . . . . . . . . . 2-81 SUBR 2 args getl . . . . . . . . . . . . 2-49 SUBR 2 args get_pname. . . . . . . . . . 2-86 SUBR 1 arg go . . . . . . . . . . . . . 2-38 FSUBR greaterp . . . . . . . . . . 2-63 LSUBR 2 or more args haipart. . . . . . . . . . . 2-65 SUBR 2 args haulong. . . . . . . . . . . 2-62 SUBR 1 arg implode. . . . . . . . . . . 2-82 SUBR 1 arg index. . . . . . . . . . . . 2-85 SUBR 2 args intern . . . . . . . . . . . 2-54 SUBR 1 arg last . . . . . . . . . . . . 2-16 SUBR 1 arg length . . . . . . . . . . . 2-16 SUBR 1 arg lessp. . . . . . . . . . . . 2-63 LSUBR 2 or more args listarray. . . . . . . . . . 2-92 LSUBR 1 or 2 args listify. . . . . . . . . . . 2-10 SUBR 1 arg loadarrays . . . . . . . . . 2-93 SUBR 1 arg log. . . . . . . . . . . . . 2-74 SUBR 1 arg lsh. . . . . . . . . . . . . 2-78 SUBR 2 args lsubrcall. . . . . . . . . . 2-12 FSUBR make_atom. . . . . . . . . . 2-86 SUBR 1 arg maknam . . . . . . . . . . . 2-82 SUBR 1 arg maknum . . . . . . . . . . . 2-28 SUBR 1 arg makunbound . . . . . . . . . 2-47 SUBR 1 arg map. . . . . . . . . . . . . 2-95 LSUBR 2 or more args mapatoms . . . . . . . . . . 2-97 LSUBR 1 or 2 args mapc . . . . . . . . . . . . 2-95 LSUBR 2 or more args mapcan . . . . . . . . . . . 2-95 LSUBR 2 or more args mapcar . . . . . . . . . . . 2-95 LSUBR 2 or more args mapcon . . . . . . . . . . . 2-95 LSUBR 2 or more args maplist. . . . . . . . . . . 2-95 LSUBR 2 or more args max. . . . . . . . . . . . . 2-64 LSUBR 1 or more args member . . . . . . . . . . . 2-23 SUBR 2 args memq . . . . . . . . . . . . 2-24 SUBR 2 args min. . . . . . . . . . . . . 2-64 LSUBR 1 or more args minus. . . . . . . . . . . . 2-65 SUBR 1 arg minusp . . . . . . . . . . . 2-61 SUBR 1 arg munkam . . . . . . . . . . . 2-28 SUBR 1 arg nconc. . . . . . . . . . . . 2-18 LSUBR 0 or more args ncons. . . . . . . . . . . . 2-15 SUBR 1 arg not. . . . . . . . . . . . . 2-4 SUBR 1 arg nreconc. . . . . . . . . . . 2-19 SUBR 2 args nreverse . . . . . . . . . . 2-19 SUBR 1 arg null . . . . . . . . . . . . 2-4 SUBR 1 arg numberp. . . . . . . . . . . 2-1 SUBR 1 arg oddp . . . . . . . . . . . . 2-61 SUBR 1 arg or . . . . . . . . . . . . . 2-32 FSUBR plist. . . . . . . . . . . . 2-51 SUBR 1 arg plus . . . . . . . . . . . . 2-67 LSUBR 0 or more args plusp. . . . . . . . . . . . 2-61 SUBR 1 arg pnget. . . . . . . . . . . . 2-52 SUBR 2 args pnput. . . . . . . . . . . . 2-53 SUBR 2 args prog . . . . . . . . . . . . 2-34 FSUBR progn. . . . . . . . . . . . 2-8 LSUBR 1 or more args progv. . . . . . . . . . . . 2-9 FSUBR putprop. . . . . . . . . . . 2-50 SUBR 3 args quote. . . . . . . . . . . . 2-5 FSUBR quotient . . . . . . . . . . 2-67 LSUBR 1 or more args random . . . . . . . . . . . 2-76 LSUBR 0 to 2 args readlist . . . . . . . . . . 2-82 SUBR 1 arg remainder. . . . . . . . . . 2-68 SUBR 2 args remob. . . . . . . . . . . . 2-55 SUBR 1 arg remprop. . . . . . . . . . . 2-51 SUBR 2 args return . . . . . . . . . . . 2-39 SUBR 1 arg reverse. . . . . . . . . . . 2-18 SUBR 1 arg rot. . . . . . . . . . . . . 2-78 SUBR 2 args rplaca . . . . . . . . . . . 2-21 SUBR 2 args rplacd . . . . . . . . . . . 2-21 SUBR 2 args samepnamep . . . . . . . . . 2-52 SUBR 2 args sassoc . . . . . . . . . . . 2-27 SUBR 3 args sassq. . . . . . . . . . . . 2-28 SUBR 3 args set. . . . . . . . . . . . . 2-46 SUBR 2 args setarg . . . . . . . . . . . 2-10 SUBR 2 args setplist . . . . . . . . . . 2-51 SUBR 2 args setq . . . . . . . . . . . . 2-45 FSUBR signp. . . . . . . . . . . . 2-61 FSUBR sin. . . . . . . . . . . . . 2-75 SUBR 1 arg sort . . . . . . . . . . . . 2-29 SUBR 2 args sortcar. . . . . . . . . . . 2-30 SUBR 2 args sqrt . . . . . . . . . . . . 2-74 SUBR 1 arg store. . . . . . . . . . . . 2-91 FSUBR stringlength . . . . . . . . 2-85 SUBR 1 arg stringp. . . . . . . . . . . 2-2 SUBR 1 arg sub1 . . . . . . . . . . . . 2-68 SUBR 1 arg sublis . . . . . . . . . . . 2-22 SUBR 2 args subrcall . . . . . . . . . . 2-11 FSUBR subrp. . . . . . . . . . . . 2-2 SUBR 1 arg subst. . . . . . . . . . . . 2-21 SUBR 3 args substr . . . . . . . . . . . 2-85 LSUBR 2 or 3 args sxhash . . . . . . . . . . . 2-25 SUBR 1 arg symeval. . . . . . . . . . . 2-12 SUBR 1 arg symeval. . . . . . . . . . . 2-46 SUBR 1 arg throw. . . . . . . . . . . . 2-40 FSUBR times. . . . . . . . . . . . 2-67 LSUBR 0 or more args typep. . . . . . . . . . . . 2-2 SUBR 1 arg xcons. . . . . . . . . . . . 2-15 SUBR 2 args zerop. . . . . . . . . . . . 2-61 SUBR 1 arg \. . . . . . . . . . . . . . 2-70 SUBR 2 args \\ . . . . . . . . . . . . . 2-70 SUBR 2 args ^. . . . . . . . . . . . . . 2-70 SUBR 2 args ^$ . . . . . . . . . . . . . 2-73 SUBR 2 args .bp Atom Index Source: MACLISP Manual 3/6/76 array. . . . . . . . . . . . 2-2 bignum . . . . . . . . . . . 2-2 car. . . . . . . . . . . . . 2-13 cdr. . . . . . . . . . . . . 2-13 defun. . . . . . . . . . . . 2-58 fixnum . . . . . . . . . . . 2-2 flonum . . . . . . . . . . . 2-2 funarg . . . . . . . . . . . 2-7 list . . . . . . . . . . . . 2-2 nil. . . . . . . . . . . . . 1-10 random . . . . . . . . . . . 2-2 string . . . . . . . . . . . 2-2 symbol . . . . . . . . . . . 2-2 zunderflow . . . . . . . . . 2-76 .bp Concept Index Source: MACLISP Manual 3/6/76 application. . . . . . . . . 1-17 lambda . . . . . . . . . . . 1-17 argument . . . . . . . . . . 1-16 lambda variable. . . . . . . 1-17 arithmetic . . . . . . . . . 2-61 lexpr. . . . . . . . . . . . 1-17 array. . . . . . . . . . . . 1-9 list . . . . . . . . . . . . 1-10 association list . . . . . . 2-26 looping. . . . . . . . . . . 2-31 atom . . . . . . . . . . . . 1-7 lsubr. . . . . . . . . . . . 1-17 atomic symbol. . . . . . . . 1-8 macro. . . . . . . . . . . . 1-17 bignum . . . . . . . . . . . 1-7 mapping. . . . . . . . . . . 2-95 binding. . . . . . . . . . . 1-13 mathematical functions . . . 2-74 binding context pointer. . . 1-24 nil. . . . . . . . . . . . . 1-8 boolean operations . . . . . 2-77 non-local exit . . . . . . . 2-31 car. . . . . . . . . . . . . 1-9 number . . . . . . . . . . . 1-7 cdr. . . . . . . . . . . . . 1-9 obarray. . . . . . . . . . . 2-54 character manipulation . . . 2-81 object . . . . . . . . . . . 1-7 character object . . . . . . 1-8 pname. . . . . . . . . . . . 2-52 comment. . . . . . . . . . . 2-8 predicate. . . . . . . . . . 2-1 cons . . . . . . . . . . . . 1-9 property . . . . . . . . . . 2-48 defining functions . . . . . 2-57 property list. . . . . . . . 2-48 dot. . . . . . . . . . . . . 1-10 quote. . . . . . . . . . . . 2-5 dotted pair. . . . . . . . . 1-10 recursion. . . . . . . . . . 2-31 eq versus equal. . . . . . . 2-2 S-expression . . . . . . . . 1-7 errors . . . . . . . . . . . 2-31 sorting. . . . . . . . . . . 2-29 evaluation . . . . . . . . . 1-16 special forms. . . . . . . . 1-21 expr . . . . . . . . . . . . 1-17 string . . . . . . . . . . . 1-9 fexpr. . . . . . . . . . . . 1-17 subr . . . . . . . . . . . . 1-17 fixnum . . . . . . . . . . . 1-7 subr-object. . . . . . . . . 1-9 flonum . . . . . . . . . . . 1-7 substitution . . . . . . . . 2-21 flow of control. . . . . . . 2-31 symbol . . . . . . . . . . . 1-8 form . . . . . . . . . . . . 1-15 t. . . . . . . . . . . . . . 1-8 fsubr. . . . . . . . . . . . 1-17 value cell . . . . . . . . . 2-45 funarg . . . . . . . . . . . 1-20 funarg problem . . . . . . . 2-6 function . . . . . . . . . . 1-15 functional property. . . . . 1-17 gensym . . . . . . . . . . . 2-55 hash table . . . . . . . . . 2-25 indicator. . . . . . . . . . 2-48 intern . . . . . . . . . . . 2-54 iteration. . . . . . . . . . 2-31