Star Sapphire Common LISP Home

Download Star Saphire
Index

LISP: DEBUG

C: DebugTog

min args: 0

max args: 1

[F][SSCL]

SYNOPSIS:

debug &optional clear-debug-if-nil-p

DESCRIPTION:

This function toggles the Star Sapphire debugger on or off.

Invoking debug toggles the behavior of the system on error or in break conditions.

If the debugger is off (the default on startup) the system returns to the top level when an error is encountered. If the debugger is on, the system invokes the debugger as if break was called when an error is encountered. The new value of the debug mode is returned as t if on or nil if off.

If an argument is given and it is NIL, debug clears the all debug modes including step, break and trace. (It does not, however, clear the trace list). Other values have no effect.

This is very useful if the debug state gets wedged; this can occur if step encounters an error and debug is not on, for instance. Once you return to the top level you may still be stepping, which is undesireable. Running (debug nil) wipes the slate clean.

Normally the debugger is enabled by calling the debug function at the top level:

LISP: (debug)

==>

t

The function returns and you are back at the top level prompt. The difference is that the default action of the error handler has been altered.

To restore the default error handler action, enter

LISP: (debug)

==>

nil

When debug is enabled, error handler calls will put you into the debugger in the current execution context. This applies to error handler calls either from runtime functions or the LISP error function. The debugger can also be invoked directly inside a LISP form using break (q.v.). Lastly, the debugger can be invoked by pressing Ctrl-Break when a process is running (although the place where the debugging starts will be fairly random in this case).

If debug is enabled, when any non-fatal error occurs, the program will be frozen at the moment the error occured. This is useful as you can examine the state of the stack at that time and track down the cause of errors.

The prompt of the debugger is

DEBUG>

The debugger exactly the same capabilities as the stepper (see step

for more details).

However, interacting with the debugger is slightly different than the stepper.

You do not need to press Enter after a command: debug commands are read directly from the keyboard and take effect immediately.

In particular, pressing the spacebar advances the evaluation one step.

The usage message for the debugger can be seen by typing a question mark:

DEBUG USAGE

<space> - one step

b - print brief backtrace

B - print verbose backtrace

e E - edit file

d D - raw stack dump

# - print number of frames

n - descend 1 frame

N - descend n frames

p - ascend 1 frame

P - ascend n frames

r R - resume evaluation

s - print bottom function

S > - print bottom frame

t - print top function

T < - print top frame

v l - describe a variable (v global, l lexical)

V L - set a variable (V global, L lexical)

q Q x X - quit, return to top level

@ - the display stack backtrace

! - run system command

~ - toggle debug mode

? - print help

 

You may obtain help by typing '?', just as in the stepper. To exit the debugger and return to the top level, you may type 'x', 'X', 'q' or 'Q'. To continue (finish) execution, you may type 'f' or 'F'.

To see how this works, enter the following from the top level and see what happens:

LISP: (debug)

t

LISP: (car (cdr (car 4)))

again from the top level prompt. Note that debug returns t or nil depending on whether debug has been enabled or disabled.

When (car 4) is encountered, press 'D' for a verbose stack dump to inspect the entire stack.

At start-up the debugger is disabled. If you are developing programs, and want the debugger enabled at start-up by default, you can insert a call to debug in the file init.lsp. If you are just using LISP to run a program which is running without problems you will probably want debug disabled. In this case ctrl-Break just returns you to the top level.

NOTES:

This facility is Star Sapphire specific although the commands were originally based on their Symbolics equivalents.

 

LISP: DECF

min args: 1

max args: 2

[M][CLTL 12]

SYNOPSIS:

decf place [delta]

DESCRIPTION:

The number produced by the form delta is added to (incf) or subtracted from (decf) the number in the generalized variable named by place, and the sum is stored back into place and returned. The form place may be any form acceptable as a generalized variable to setf. If delta is not supplied, then the number in place is changed by 1. For example:

(setq n 0)

(incf n) => 1 and now n => 1

(decf n 3) => -2 and now n => -2

(decf n -5) => 3 and now n => 3

(decf n) => 2 and now n => 2

The effect of (incf place delta) is roughly equivalent to

(setf place (+ place delta))

except that the latter would evaluate any subforms of place twice, whereas incf takes care to evaluate them only once. Moreover, for certain place forms incf may be significantly more efficient than the setf version.

SEE ALSO:

incf

NOTES:

This function is implemented using a macro which is loaded at initialization in defsetf.fsl. In order to use a given setf method, you must use defsetf to define that forms' setf method. If you get the message that decf does not know about a particular forms' setf method, you must edit init0.lsp and use the setf method for that form. Only the setf methods for car and cdr are loaded at startup.

 

LISP: DECLARE

C: SFCDecl

[S][CLTL 9]

SYNOPSIS:

declare{decl-spec}*

DESCRIPTION:

A declare form is known as a declaration. Declarations may occur only at the beginning of the bodies of certain special forms; that is, a declaration may occur only as a statement of such a special form, and all statements preceding it (if any) must also be declare forms (or possibly documentation strings, in some cases). Declarations may occur in lambda-expressions and in the forms listed here.

defmacro dotimes

defun let

do* let*

do prog

dolist prog*

It is an error to attempt to evaluate a declaration. Those special forms that permit declarations to appear perform explicit checks for their presence.

It is permissible for a macro call to expand into a declaration and be recognized as such, provided that the macro call appears where a declaration may legitimately appear. (However, a macro call may not appear in place of a decl-spec.)

Each decl-spec is a list whose car is a symbol specifying the kind of declaration to be made. Declarations may be divided into two classes: those that concern the bindings of variables, and those that do not. (The special declaration is the sole exception: it effectively falls into both classes, as explained below.) Those that concern variable bindings apply only to the bindings made by the form at the head of whose body they appear. For example, in

(defun foo (x) (declare (type float x)) ...

(let ((x 'a)) ...)

...)

the type declaration applies only to the outer binding of x, and not to the binding made in the let.

Declarations that do not concern themselves with variable bindings are pervasive, affecting all code in the body of the special form. As an example of a pervasive declaration,

(defun foo (x y) (declare (notinline floor)) ...)

advises that everywhere within the body of foo the function floor should not be open-coded but called as an out-of-line subroutine.

Some special forms contain pieces of code that, properly speaking, are not part of the body of the special form. Examples of this are initialization forms that provide values for bound variables, and the result forms of iteration constructs. In all cases such additional code is within the scope of any pervasive declarations appearing before the body of the special form. Non-pervasive declarations have no effect on such code, except (of course) in those situations where the code is defined to be within the scope of the variables affected by such non-pervasive declarations. For example:

(defun few (x &optional (y *print-circle*))

(declare (special *print-circle*))

...)

The reference to *print-circle* in the first line of this example is special because of the declaration in the second line.

(defun nonsense (k x z)

(foo z x) ;First call to foo

(let ((j (foo k x)) ;Second call to foo

(x (* k k)))

(declare (inline foo) (special x z))

(foo x j z))) ;Third call to foo

In this rather nonsensical example, the inline declaration applies to the second and third calls to foo, but not to the first one. The special declaration of x causes the let form to make a special binding for x, and causes the reference to x in the body of the let to be a special reference. The reference to x in the second call to foo is also a special reference. The reference to x in the first call to foo is a local reference, not a special one. The special declaration of z causes the reference to z in the call to foo to be a special reference; it will not refer to the parameter to nonesense named z, because the parameter of z does not appear in the body of the defun, but in an inner construct, and therefore does not affect the binding of the parameter.)

 

LISP: DECODE-UNIVERSAL-TIME

C: DUT

min args: 1

max args: 2

[F][CLTL]

SYNOPSIS:

decode-universal-time universal-time &optional time-zone

DESCRIPTION:

The universal time value is converted into decoded time format. Nine values are returned: second, minute, hour, date, year,day-of-week, daylight-savings-time-p and time-zone.

The second argument, if present, converts the result relative to the given time zone. If specified, there is no daylight savings time handling.

NOTES:

See time functions for a description of decoded time format, and an explanation of how to set the default time-zone.

 

LISP: DEFCLASS

C: SFCDefclass, Defclass

[M][CLOS]

SYNOPSIS:

defclass class-name ({superclass-name}*) ({slot-specifier}*)

class-name ::= symbol

superclass-name ::= symbol

slot-specifier ::= slot-name | (slot-name [[^slot-option]])

slot-name :: symbol

slot-option ::=

{ :accessor reader-function-name }*

| { :allocation allocation-type }*

| { :initarg initarg-name }*

| { :initform form }

| { :type type-specifier }

reader-function-name ::= symbol

function-name ::= symbol

initarg-name ::= symbol

allocation-type ::= :instance | :class

 

DESCRIPTION:

The macro defclass defines a new named class. It returns the new class object as its result.

The syntax of defclass provides options for specifying initialization arguments for slots, default initialization values for slots, and for requesting that methods on specified generic functions be automatically generated for reading and writing the value of slots.

Defining a new class also causes a type of the same name to be initialized. The predicate (typep object class-name) returns t if the class of the given object is class-name itself or a subclass of class.

The class-name argument is a non-nil symbol. It becomes the proper name of the new class. If a class with the same proper name already exists and the t class is an instance of standard-class, and if the defclass form for the definition of the new class also specifies a class of class standard-class, the definition of the existing class is replaced.

Each superclass-name argument is a non-nil symbol that specifies a direct superclass of the new class. The new class will inherit slots and methods from each of its direct superclasses, from their direct superclasses, etc.

Each slot-specifier argument is the name of a slot or a list consisting of the slot name followed by zero or more slot options. The slot-name argument is a symbol that is syntactically valid for use as a variable name. If there are any duplicate slot names, an error is signaled.

The following slot options are implemented in the current version of Star Sapphire CLOS. Other options, specified by ANSI CLOS, are recognized in a defclass form but have no effect.

The :accessor slot option specifies that an unqualified method is to be defined on the generic function reader-function-name to read the value of the given slot and that an unqualifier (setf reader-function-name) to be used with setf to modify the value of the slot. The reader-function-name argument is a non-nil symbol. The :accessor slot option may be specified more than once for a given symbol.

The :allocation slot option is used to specify where storage is to be allocated for the given slot. Storage for a slot may be located in each instance or in the class object itself, for example. The value of the allocation-type argument can be either the keyword :instance or the keyword :class.

The :allocation slot option may be specified at most once for a given slot. If the :allocation slot option is not specified, the effect is the same as specifying :allocation :instance. If allocation-type is :instance, a local slot of the given name is allocated in each instance of the class.

If allocation-type is :class, a shared slot of the given name is allocated. The value of the slot is shared by all instances of the class. If a class C1 defines such a shared slot, any subclass C2 of C1 will share this single slot unless the defclass form for C2 specifies a slot of the same name or there is a superclass of C2 that precedes C1 in the class precedence list of C2 and that defines a slot of the same name.

The :initform slot option is used to provide a default initial value form to be used in the initialization of the slot. The :initform slot option may be specified at most once for a given slot. This form is evaluated every time it is used to initialize the slot. The lexical environment in which this form is evaluated is the lexical environment in which the defclass form was evaluated. Note that the lexical environment refers to both variables and to functions. For local slots, the dynamic environment is the dynamic environment in which make-instance was called; for shared slots, the dynamic environment is the dynamic environment in which the defclass was evaluated.

The :initarg slot option declares an initialization argument named initarg-name and specifies that this initialization argument initializes the given slot. If the initialization argument has a value in the call to initialize-instance, the value will be stored into the given slot and the slots :initform slot option, if any is not evaluated. If none of the intialization arguments specified for a given slot has a value, the slot is initialized according to the :initform slot option, if specified. The :initarg slot option can be specified more than once for a given slot. The initarg-name argument can be any symbol.

The :type slot option specifies that the contents of the slot will always be of the specified data type. It effectively declares the result type of the reader generic function when applied to an object of this class. The result of attempting to store in a slot a value that does not satisfy the type of the slot is undefined. The :type slot option may be specified at most once for a given slot.

The new class object is returned as the result.

 

LISP: DEFCONSTANT

C: EDefConst

min args: 2

max args: 3

[M][CLTL 5]

SYNOPSIS:

defconstant name value [documentation]

DESCRIPTION:

The defconstant macro defines a named constant with a specified value. This form asserts that the value of the variable name is fixed and prohibits any other form from changing its value. However, successive defconstant calls can be used to redefine a constant if desired.

The value argument is evaluated and assigned as the global value of the symbol name.

The return value of defconstant is the name declared.

Defconstant is normally used only as a top-level form.

It is an error if there are any special bindings of the variable at the time the defconstant form is executed.

Once a name has been declared by defconstant to be constant, any further assignment to or binding of that special variable is an error.

This form is used to define such standard constants as pi, least-positive-short-float, and lambda-list-keywords. The code to do so can be found in init0.lsp; this can be added to your startup sequence by transferring their definitions to init.lsp or any other file of LISP code.

Some forms such as nil and t are inherently defined as if by defconstant.

The optional documentation argument must be a string.

IMPLEMENTATION NOTE:

In Star Sapphire, a constant symbol is simply marked by the property defconstant with value t in its property list. All forms which try to assign or bind a value to a global symbol look for this property and refuse to do so if it is found.

Hence a plausible (but completely unportable) way to make a symbol with a value assigned by defconstant re-assignable is as follows:

(defmacro undefconstant (x)

`(if (and (symbolp ',x)(boundp ',x)(constantp ',x))

(remprop ',x 'defconstant)))

(undefconstant pi)

(defconstant pi 3.0

"the ratio between a circles circumfrence and its radius -- NOT!")

This is handy if you are loading a set of defconstants in a file over and over in the course of debugging them and get tired of commenting them the file the second time.

We can't guarantee that this behavior will be preserved in future versions of the product, but it will work fine with the current version.

LISP: DEFMACRO

C: SFCDefMac, EDefMac

[M][CLTL 8]

SYNOPSIS:

defmacro name lambda-list {declaration | doc-string}* {form}*

DESCRIPTION:

defmacro is a macro-defining macro that arranges to decompose the macro-call form in an elegant and useful way. defmacro has essentially the same syntax as defun: name is the symbol whose macro definition we are creating, lambda-list is similar in form to a lambda-list, and the forms constitute the body of the expander function. The defmacro construct arranges to install this expander function, as the global macro definition of name. The expander function is effectively defined in the global environment; lexically scoped entities established outside the defmacro form that would ordinarily be lexically apparent are not visible within the body of the expansion function. The name is returned as the value of the defmacro form.

It is permissible to redefine a function as a macro or vice-versa. It is an error to try to redefine a built-in special form as a macro.

If we view the macro call as a list containing a function name and some argument forms, in effect the expander function and the list of (unevaluated) argument forms is given to apply. The parameter specifiers are processed as for any lambda-expression, using the macro-call argument forms as the arguments. Then the body forms are evaluated as an implicit progn, and the value of the last form is returned as the expansion of the macro call.

If the optional documentation string doc-string is present (if not followed by a declaration, it may be present only if at least one form is also specified, as it is otherwise taken to be a form), then it is attached to the name as a documentation string of type function; see documentation.

Like the lambda-list in a defun, a defmacro lambda-list may contain the lambda-list keywords &optional, &rest, &key, &allow-other-keys, and &aux. For &optional and &key parameters, initialization forms and supplied-p parameters may be specified, just as for defun. Two additional markers are allowed in defmacro variable lists only:

&body

This is identical in function to &rest, but it informs certain output-formatting and editing functions that the remainder of the form is treated as a body, and should be indented accordingly. (Only one of &body or &rest may be used.)

&whole

This is followed by a single variable that is bound to the entire macro-call form; this is the value that the macro definition function receives as its single argument. &whole and the following variable should appear first in the lambda-list, before any other parameter or lambda-list keyword.

 

LISP: DEFMETHOD

C: SFCDefmethod, Defmethod

[M][CLOS]

SYNOPSIS:

defmethod function-name {method-qualifier}* specialized-lambda-list

[[{declaration}* | doc-string ]] {form}*

DESCRIPTION:

The defmethod macro defines a method on a generic function.

If the function named function-name has a functional definition, a generic function is created with default values for the argument precedence order (each argument is more specific than the arguments to the right in the argument list), for the generic function class (the class standard-generic-function), for the method class (the class standard-method), and for the method combination type (the standard method combination type). The lambda-list of the generic function is congruent with the lambda-list of the method being defined; if the defmethod form mentions keyword arguments, the lambda-list of the generic function will mention &key (but no keyword arguments). If function-name names a non-generic function, a macro or a special form, an error is signaled.

If the generic function is currently named by function-name, where function-name is a symbol or a list of the form (setf symbol),the lambda-list of the method must be congruent with the lambda-list of the generic function. If this condition does not hold, an error is signaled.

The function-name argument is a non-nil symbol; it names the generic function on which the method is defined.

Each method-qualifier object is an object that is used by method combination to identify the given method. A method qualifier is a non-nil atom. The method combination type may further restrict what a method qualifier may be. The standard method combination type allows for unqualified methods or methods whose sole qualifier is the keyword :before or :after. The CLOS specification allows for a further :around keyword in this context, but this is not supported yet in Star Sapphire CLOS.

A specialized-lambda-list is like an ordinary lambda-list except that the name of a required parameter can be replaced by a specialized parameter, a list of the form (variable-name parameter-specializer-name). Only required parameters may be specialized. A parameter specializer or name is a symbol that names a class or (eql eql-specializer-form). The parameter specializer name (eql eql-specializer form) indicates that the corresponding argument must be eql to the object that is the value of eql-specializer-form for the method to be applicable. If no parameter specializer name is specified for a given method, the parameter specializer defaults at the class named t.

The form arguments specify the method body. The body of the method is enclosed in an implicit block. This block bears the same name as the generic function.

The result of defmethod is the method object.

The class of the method object that is created is that given by the method class option of the generic function on which the method is defined.

If the generic function already has a method that agrees with the method being defined on parameter specializers and qualifiers, defmethod replaces the existing method with the one now being defined.

 

LISP: DEFPARAMETER

C: EDefParam

min args: 2

max args: 3

[M][CLTL 5]

SYNOPSIS:

defparameter name initial-value [documentation]

DESCRIPTION:

A defparameter form declares a global variable named name (which must be a symbol) and assigns it an initial value. The return value from the form is name.

The initial-value form is evaluated. The result is assigned as the global value of the variable. This value can be changed by other forms which can assign to global variables. However, the intent of using this form is that the global value defined by defparameter is intended to normally be constant but can be changed; such a change is to be considered a change to the program.

defparameter normally is used only as top-level form.

defparameter is similar to defvar. However defparameter requires the initial-value form, and always evaluates it when the form is evaluated.

The optional documentation argument must be a string.

 

LISP: DEFSTRUCT

[M][CLTL 19]

SYNOPSIS:

defstruct {name | (name &key :conc-name :constructor :copier :predicate)}

[doc-string]

{slot-name | (slot-name default-value &key :type :read-only)}+

DESCRIPTION:

The defstruct macro defines a record or structure data type.

The defstruct macro allows the definition of structures. Structures are new data types which are programmer defined, consisting of a set of named slots. The overall intent corresponds to the construct called a record or struct in other programming languages.

A defstruct form, when evaluated, creates a set of functions which are can then access each particular slot in the structure, and to make, copy and distinguish instances of the structure. The defstruct form returns the name of the structure created.

These functions are like any other LISP defuns but are created and defined automatically while evaluating a defstruct form. Although there are default names for these functions based on placing a prefix before the name of the structure, options allow the functions to be given any desired name.

Slots have values: A slot value can be any LISP object. However, individual slots can be defined to accept values of a particular type or to be read-only. The slot access functions have automatically generated setf methods and thus the slots are effectively fully generalized variables (see setf).

A simple example of a defstruct is as follows:

(defstruct person last-name phone social-security) ==> PERSON

This defines a structure called a person with three slots: last-name, phone, and social-security. The name of the new structure is returned.

After defining this, the function make-person has been created and will return a new instance of the structure, which we assign to the symbol jane:

(setq jane

(make-person)) ==>

#S(PERSON LAST-NAME NIL PHONE NIL SOCIAL-SECURITY NIL)

The #S() syntax is how structure data is printed in Common LISP.

The first symbol in the parentheses is the name of the structure; following this is each slot's name alternated with its value. As no values have been assigned to the slots, they will be nil.

Now to set values for slots for jane. The person-last-name, person-phone and person-social-security functions have been created for this purpose automatically when the defstruct was executed, and they are fully setf-able:

(setf (person-last-name jane) 'johnson)

(setf (person-phone jane) "408-555-5555")

(setf (person-social-security jane) "551-95-9655")

and hencforth, to obtain jane's social security number we can write:

(person-social-security jane) ==> "551-95-9655"

This is actually the hard way to initialize a struct instance. The slot names automatically become keywords to the make-person function and can be used to set initial values for given slots when allocating an instance. Therefore we could have coded:

(setq jane

(make-person

:last-name 'johnson

:phone "408-555-5555"

:social-security "551-95-9655")) ==>

#S(PERSON LAST-NAME JOHNSON PHONE "408-555-5555" SOCIAL-SECURITY "551-95-9655")

As can be seen from the return value from setq, the structure's fields have been initialized.

Anatomy of a Defstruct

The defstruct form has three portions: A name and options clause; an optional documentation string; followed by one or more slot description clauses.

Name and Options clause

The name and options clause looks like:

{name | (name &key :conc-name :constructor :copier :predicate)}

The name and options clause can either consist simply of the symbol which names the struct; or a list with the name at the head and a set of keyword options.

The name of the structure must be a symbol; it becomes the name of a new data type consisting of all instances of the structure. The function typep will accept and use this name as appropriate:

(typep jane 'person) ==> t

If the optional documentation string doc-string is present, then it is attached to the name as a documentation string of type structure; see documentation.

Usually no options are needed at all. If no options are specified, then one may write simply name instead of (name) after the word defstruct.

The following options are available in this implementation:

:conc-name

This provides for automatic prefixing of names of access functions. It is conventional to begin the names of all the access functions of a structure with a specific prefix, the name of the structure followed by a hyphen. This is the default behavior.

The argument to the :conc-name option specifies an alternate prefix to be used. (If a hyphen is to be used as a separator, it must be specified as part of the prefix.) If nil is specified as an argument, then no prefix is used; then the names of the access functions are the same as the slot names, and it is up to the programmer to name the slots reasonably.

For instance, if the person structure was specified as:

(defstruct (person :conc-name NIL) last-name phone social-security)

==> PERSON

then

(setf (last-name jane) 'johnson)

would be an example of the format of an access function.

Or person could be defined as

(defstruct (person :conc-name human-) last-name phone social-security)

==> PERSON

then

(setf (human-last-name jane) 'johnson)

can be written.

:constructor

This option specifies the name of the constructor function. If the argument is not provided or if the option itself is not provided, the name of the constructor is produced by concatenating the string "MAKE-" and the name of the structure. If the argument is provided and is nil, no constructor function is defined.

For instance, if the person structure was specified as:

(defstruct (person :constructor 'create-) last-name phone social-security)

==> PERSON

then we can code:

(setq jane

(create-person

:last-name 'johnson

:phone "408-555-5555"

:social-security "551-95-9655")) ==>

#S(PERSON LAST-NAME JOHNSON PHONE "408-555-5555" SOCIAL-SECURITY "551-95-9655")

:copier

This option specifies the name of the copier function.

If the argument is not provided or if the option itself is not provided, the name of the copier is produced by concatenating the string "COPY-" and the name of the structure. If the argument is provided and is nil, no copier function is defined.

The automatically defined copier function simply makes a new structure and transfers all components verbatim from the argument into the newly created structure. No attempt is made to make copies of the components. Corresponding components of the old and new structures will therefore be eql.

:predicate

This option specifies the name of the type predicate.

If the argument is not provided or if the option itself is not provided, the name of the predicate is made by concatenating the name of the structure to the string "-P", If the argument is provided and is nil, no predicate is defined.

:include

This option is used to build a new structure definition which incorporates a previously defined structure. The :include option causes the structure being defined to have the same slots as the included structure; in addition, all access functions for the included structure are usable by the structure being defined. For instance, if you define a structure named customer.

(defstruct (customer (:include person)) credit-rating customer-since)

Then customer includes all of the fields in person.

The :include option with defstruct has been largely superceeded by the use of defclass, which supports a very flexible form of multiple inheritance.

Slot Descriptions

Following the name-and-options clause and the optional documentation string are one or more slot descriptions.

Each slot-description is of the form:

{slot-name | (slot-name default-value &key :type :read-only)}+

Each slot-name must be a symbol. An access function is defined for each slot. The name of the access function is the conc-name prefix concatenated with the name of the slot. The conc-name prefix can be specified through the :conc-name option (see above). If not specified, it is the name of the structure with a dash.

If no slot options and no default-value are specified, then one may write simply slot-name instead of (slot-name) as the slot description. The default-value is a form that is evaluated each time a structure is to be constructed; the value is used as the initial value of the slot. If no default-value is specified, then the initial content of a slot will be nil.

slot options

There are two slot options, :type and :read-only. Note that it is impossible to specify a slot option without specifying a default-value for the slot, even if it is nil.

:type

The :type slot option specifies that objects contained in the given slot must be of a specified type. It is an error to assign a value of the wrong type to this slot.

:read-only

The :read-only slot option specifies that this slot may not be altered.

The slot will always contain the value specified at construction time. It is an error to try to change the value of the slot. This value must not be nil. If the argument to this option is nil, this slot-option has no effect. Note that the argument to this option is not evaluated.

For instance, if we want to add a slot number-of-eyes to our person structure, we can be reasonably sure that

(defstruct person last-name phone social-security

(number-of-eyes 2 :read-only t)) ==> PERSON

Here is another example:

(setq *default-ship-mass* 200)

(defstruct ship

"a space ship" ; documentation string

(x-position 1.0 :type float)

(y-position 2.0 :type float)

(x-velocity 3.0 :type float)

(y-velocity 4.0 :type float)

(mass *default-ship-mass*)

(name foo-bar))

(setq enterprise

(make-ship :name 'enterprise

:x-position 4.5

:y-velocity 300000.3))

; and then....

(ship-x-position enterprise) ==> 4.5

(setf (ship-y-position enterprise) 4.0)

(ship-y-position enterprise) ==> 4.0

(ship-x-velocity enterprise) ==> 3.0

(ship-y-velocity enterprise) ==> 300000.3

(ship-name enterprise)) ==> ENTERPRISE

 

LISP: DEFUN

C: SFCDefun, EDefun

min args: 2

max args: -1

[M][CLTL 7]

SYNOPSIS:

defun name lambda-list {declaration | doc-string}* {form}*

DESCRIPTION:

Evaluating a defun form causes the symbol name to become a global name for the functional object specified by the lambda-expression

(lambda lambda-list {declaration | doc-string}* {form}*)

defun forms normally appear at top level.

A function defined in this fashion is colloquially called a defun.

The entry for lambda is essential reading to understand the format of defuns' parameter list.

The documentation string is accepted and used as the documentation value for the function; otherwise it has no influence on the behavior of the function at runtime.

If the documentation string is not followed by a declaration, it may be present only if at least one form is also specified, as it is otherwise taken to be a form. It is an error if more than one doc-string is present.

The forms constitute the body of the defined function; they are executed as an implicit progn. This means that they are executed in sequence and return the value of the last executed form.

The body of the defined function is implicitly enclosed in a block construct whose name is the same as the name of the function.

Therefore return-from may be used to prematurely exit from the function.

The return value of a defun is the name of the function which has been defined.

For example:

(defun tak (x y z)

"This defines the heavily recursive 'Takeuchi' function."

(if (not (< y x))

(return-from tak z) ; not really needed, but instructive

(tak (tak (1- x) y z)

(tak (1- y) z x)

(tak (1- z) x y))))

and this can also be written:

(defun tak (x y z)

(if (not (< y x))

z ; since the 'if' evaluates in this case to z

; and the defun returns what 'if' returns.

(tak (tak (1- x) y z)

(tak (1- y) z x)

(tak (1- z) x y))))

NOTES:

It is permissible to use defun to redefine a function, or to install a corrected version of an incorrect definition, for example. It is permissible to redefine a macro as a function. It is an error to attempt to redefine the name of a special form as a function.

Technically speaking, the functional object which the defun names is the result of evaluating the lambda expression in the lexical environment which it is defined in; since this is a top-level form, it is most typically created in a null lexical environment; so under most conditions this is a moot point.

LISP: DEFVAR

C: EDefVar

min args: 1

max args: 3

[M][CLTL 5]

SYNOPSIS:

defvar name [initial-value [documentation]]

DESCRIPTION:

The defvar form defines a special variable with name The name argument must be a symbol. Optionally, an initial-value, which can be any LISP form is specified for the variable. The return value is the name argument.

The optional documentation argument must be a string.

defparameter normally is used only as a top-level form.

defvar is the recommended way to declare the use of a special variable in a program.

If an initial value is specified for the variable, then if the variable is unbound it is initialized to the result of evaluating the initial-value form. If the variable currently has a global definition, the intial-value form is retained until the first time that the variable is used. At that time and not before, the initial-value form will be evaluated and then assigned to the symbol named by the variable.

NOTE:

The behavior of defvar regarding the initial-value argument is useful if initial-value does something expensive such as allocating and initializing a complicated data structure.

 

LISP: DELETE

C: Ldel

min args: 2

max args: -1

[F][CLTL 14]

SYNOPSIS:

delete item sequence &key :from-end :test :test-not

:start :end :count :key

DESCRIPTION:

The delete function returns a sequence of the same kind as the sequence argument. The value has the same elements except that the those in the subsequence from :start to :end, satisfying the test will be deleted.

The function is destructive. The sequence argument is destroyed and used to construct the result; the value will not be eq to sequence. Elements not deleted occur in the same order as they did in the argument.

The :count argument if supplied limits the number of elements deleted; if more than :count elements satisfy the other conditions then only :count leftmost elements are deleted, unless :from-end is non-nil, in which case :count rightmost elements are deleted.

 

LISP: DELETE-FILE

C: Ldelete_file

min args: 1

max args: 1

[F][CLTL]

SYNOPSIS:

delete-file file

DESCRIPTION:

The file is deleted. The file argument must be a string or a symbol. If the operation is not sucessful, a system error is signaled. Otherwise, t is returned.

 

LISP: DELETE-IF

C: Ldelif

min args: 2

max args: -1

[F][CLTL 14]

SYNOPSIS:

delete-if item sequence &key :from-end :test :test-not :start :end :count :key

DESCRIPTION:

See delete.

 

LISP: DELETE-IF-NOT

C: Ldelifn

min args: 2

max args: -1

[F][CLTL 14]

SYNOPSIS:

delete-if-not item sequence &key :from-end :test :test-not :start :end :count :key

DESCRIPTION:

See delete.

 

LISP: DELETE-PACKAGE

C: DelPackage

min args: 1

max args: 1

[F][CLTL]

SYNOPSIS:

delete-package package

DESCRIPTION:

delete-package deletes the specified package from all package system data structures. The package argument may be either a package or the name of a package.

If package is a name but there is currently no package of that name, an error is signaled. Upon this error, LISP makes no deletion attempt.

If package is a package object that has already been deleted, no error is signaled and no deletion is attempted; instead, delete-package immediately returns nil.

If the package specified for deletion is currently used by other packages, an error is signaled. Upon this error, the effect of the function unuse-package is performed on all such other packages so as to remove their dependency on the specified package as if no other package had If any symbol had the specified package as its home package before the call of delete-package, then its home package is unspecified (that is, the contents of its package cell are unspecified) after the delete-package operation has been completed. Symbols in the deleted package are not modified in any other way.

The name and nickanames of the package cease to be recognized package names. The package object is still a package, but anonymous; packagep will be true of it, but package-name applied to it will return nil.

The effect of any other package operation on a deleted package object is undefined. In particular, an attempt to locate a symbol within a deleted package (using intern or find-symbol, for example,) will have unspecified results.

delete-package returns t if the deletion succeeds, and nil otherwise.

 

LISP: DENOMINATOR

C: Ldenominator

min args: 1

max args: 1

[F][CLTL 12]

SYNOPSIS:

denominator rational

DESCRIPTION:

This function takes a rational number (an integer or ratio) and returns as an integer the denominator of the canonical reduced form of the rational. The denominator of an integer is 1 .Note that:

(gcd (numerator x) denominator x)) => 1

The denominator will always be a strictly positive integer.

(denominator (/ 8 -6)) => 3

 

LISP: DESCRIBE

C: L_Describe

min args: 1

max args: 1

[F][CLTL 25]

SYNOPSIS:

describe object

DESCRIPTION:

describe prints, to the stream which is the value of the variable *standard-output*, information about the object.

describe returns no values (that is, it returns what the expression (values) returns: Zero values).

NOTES:

The #? syntax can be used as a shorthand for describe in Star Sapphire.

 

LISP: DIGIT-CHAR

C: Ldigit_char

min args: 1

max args: 3

[F][CLTL 13]

SYNOPSIS:

digit-char weight &optional (radix 10)(font 0)

DESCRIPTION:

digit-char returns a character object whose code has the result weight when used as a digit in the radix (which defaults to base 10, but optionally can take any value between 2 and 32 inclusive). If no such character can be produced, digit-char returns nil.

The uppercase letter is produced if an alphabetic letter is the result.

NOTES:

The optional font argument, which defaults to 0, allows specification of a font attribute; this has no effect in Star Sapphire and has been eliminated from ANSI Common LISP.

 

LISP: DIGIT-CHAR-P

C: LDigCharP

min args: 1

max args: 2

[F][CLTL 13]

SYNOPSIS:

digit-char-p char &optional (radix 10)

DESCRIPTION:

The argument char must be a character object, and radix must be a non-negative integer. If char is not a digit of the radix specified by radix, then digit-char-p is false; otherwise it returns a non-negative integer that is the "weight" of char in that radix.

Digits are necessarily graphic characters.

Of the standard characters (as defined by standard-char-p), the characters 0 through 9, A through Z, and a through z are digits. The weights of 0 through 9 are the integers 0 through 9, and of A through Z (and also a through z) are 10 through 35. Digit-char-p returns the weight for one of these digits if and only if its weight is strictly less than radix. Thus, for example, the digits for radix 16 are

0 1 2 3 4 5 6 7 8 9 A B C D E F

Here is an example of the use of digit-char-p:

(defun convert-string-to-integer (str &optional (radix 10))

"Given a digit string and optional radix, return an integer."

(do ((j 0 (+ j 1))

(n 0 (+ (* n radix)

(or (digit-char-p (char str j) radix)

(error "Bad radix-~D digit: ~C"

radix

(char str j))))))

((= j (length str)) n)))

 

LISP: DIRECTORY

C: Ldirectory

min args: 1

max args: 1

[F][CLTL]

SYNOPSIS:

directory path

DESCRIPTION:

This function returns a list of strings which are all file names specified by path which must be a string or symbol.

The path argument works just like a dos 'DIR' argument; it can consist of a path and a mask or just a file mask.

EXAMPLES:

(directory "*.*") ; all files in the current directory

(directory "e:\\tmp\\*.tmp") ; all files with .tmp extension in

; the directory e:tmp

 

 

LISP: DISASSEMBLE

C: Ldisasm

min args: 1

max args: 2

[F][CLTL 25]

SYNOPSIS:

disassemble symbol &optional function-type

DESCRIPTION:

If a second argument is not specified, return the functional definition of symbol; otherwise function-type should be one of:

macro

return the macro function for symbol for function or macro, nil is returned if no such value.

cname

return the name of the C function associated with the functional object, or nil if there is none.

 

LISP: DO

see DO and DO*

 

LISP: DO*

see DO and DO*

 

LISP: DO and DO*

C: SFCDos, EDo; SFCDos, EDoStar

[M][CLTL 7]

SYNOPSIS:

do ({(var [init [step]])}*) (end-test {result}*)

{declaration}* {tag | statement}*

do* ({(var [init [step]])}*) (end-test {form}*)

{declaration}* {tag | statement}*

DESCRIPTION:

The do special form provides a generalized iteration facility, with an arbitrary number of "index variables." These variables are bound within the iteration and stepped in parallel in specified ways. They may be used both to generate successive values of interest (such as successive integers) or to accumulate results. When an end condition is met, the iteration terminates with a specified value.

In general, a do loop looks like this:

(do ((var1 init1 step1)

(var2 init2 step2)

...

(varn initn stepn))

(end-test . result)

{declaration}*

. tagbody)

A do* loop looks exactly the same except that the name do is replaced by do*.

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, and a stepping form step. If init is omitted, it defaults to nil. If step is omitted, the var is not changed by the do construct between repetitions (though code within the do is free to alter the value of the variable by using setq).

An index-variable specifier can also be just the name of a variable. In this case, the variable has an initial value of nil and is not changed between repetitions. As a matter of style, it is recommended that an unadorned variable name be written only when that variable will be stored into (such as by setq) before its use. If it is important that the initial value is nil rather than some undefined value, then it is clearer to write out (varj nil) if the initial value is intended to mean "false" or (varj +()) if the initial value is intended to be an empty list.

Before the first iteration, all the init forms are evaluated, and each var is bound to the value of its respective init. This is a binding, not an assignment; when the loop terminates, the old values of those variables will be restored. For do, all of the init forms are evaluated before any var is bound; hence all the init forms may refer to the old bindings of all the variables (that is, to the values visible before beginning execution of the do construct). For do*, the first init form is evaluated, then the first var is bound to that value, then the second init form is evaluated, then the second var is bound, and so on; in general, the initj form can refer to the new binding vark if k < j, and otherwise to the old binding of vark.

The second element of the loop is a list of an end-testing predicate form end-test and zero or more result forms. This resembles a cond clause. At the beginning of each iteration, after processing the variables, the end-test is evaluated. If the result is nil, execution proceeds with the body of the do (or do*) form. If the result is not nil, the result forms are evaluted in order as an implicit progn, and then do returns. do returns the results of evaluating the last result form. If there are no result forms, the value of do is nil. Note that this is not quite analogous to the treatment of clauses in a cond form, because a cond clause with no result forms returns the (non-nil) result of the test.

At the beginning of each iteration other than the first, the index variables are updated as follows. All the step forms are evaluated, from left to right, and the resulting values are assigned to the respective index variables. Any variable that has no associated step form is not assigned to. For do, all the step forms are evaluated before any variable is updated; the assignment of values to variables is done in parallel, as if by psetq. Because all of the step forms are evaluated before any of the variables are altered, a step form when evaluated always has access to the old values of all the index variables, even if other step forms precede it. For do*, the first step form is evaluated, even if other step forms precede it. For do*, the first step form is evaluated, then the value is assigned to the first var, then the second step form is evaluated, then the value is assigned to the second var, and so on; the assignment of values to variables is done sequentially, as if by setq. For either do or do*, after the variables have been updated, the end-test is evaluated as described above, and the iteration continues.

If the end-test of a do form is nil, the test will never succeed. Therefore this provides an idiom for "do forever": The body of the do is executed repeatedly, stepping variables as usual. (The loop construct performs a "do forever" that steps no variables.) The infinite loop can be terminated by the use of return, return-from, go to an outer level, or throw. For example:

(do ((j 0 (+ j 1)))

(nil) ;Do forever

(format t "~%Input ~D:" j)

(let ((item (read)))

(if (null item) (return) ;Process items until nil seen.

(format t "~&Output ~D: ~S" j (process item)))))

The remainder of the do form constitutes an implicit tagbody. Tags may appear within the body of a do loop for use by go statements appearing in the body (but such go statements may not appear in the variable specifiers, the end-test, or the result forms). When the end of a do body is reached, the next iteration cycle (beginning with the evaluation of step forms) occurs.

An implicit block named nil surrounds the entire do form. A return statement may be used at any point to exit the loop immediately.

declare forms may appear at the beginning of a do body. They apply to code in the do body, to the bindings of the do variables, to the init forms, to the step forms, to the end-test, and to the result forms.

Here are some examples of the use of do:

(do ((i 0 (+ i 1)) ;Sets every null element of a-vector to zero.

(n (length a-vector)))

((= i n))

(when (null (aref a-vector i))

(setf (aref a-vector i) 0)))

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.

Very often an iterative algorithm can be most clearly expressed entirely in the step forms of a do, and the body is empty. For example,

(do ((x foo (cdr x))

(y bar (cdr y))

(z '() (cons (f (car x) (car y)) z)))

((or (null x) (null y))

(nreverse z)))

does the same thing as (mapcar #+f foo bar). Note that the step computation for z exploits the fact that variables are stepped in parallel. Also, the body of the loop is empty. Finally, the use of nreverse to put an accumulated do loop result into the correct order is a standard idiom. Another example:

(defun list-reverse (list)

(do ((x list cdr x))

(y '() (cons (car x) y)))

((endp x) y)))

Note the use of endp rather than null or atom to test for the end of a list; this may result in more robust code.

As an example of nested loops, consider a list of conses. The car of each cons is a list of symbols, and the cdr of each cons is a list of equal length containing corresponding values. Such a data structure resembles a rib-cage. A lookup function on such a data structure might be:

(defun ribcage-lookup (sym ribcage)

(do ((r ribcage (cdr r)))

((null r) nil)

(do ((s (caar r) (cdr s))

(v (cdar r) (cdr v)))

((null s))

(when (eq (car s) sym)

(return-from ribcage-lookup (car v))))))

(Notice the use of indentation in the above example to set off the bodies of the do loops.)

A do loop may be explained in terms of the more primitive constructs block, return, let, loop, tagbody, and psetq as follows:

(block nil

(let ((var1 init1)

(var2 init2)

...

(varn initn))

{declaration}*

(loop (when end-test (return (progn . result)))

(tagbody . tagbody)

(psetq var 1 step1

var2 step2

...

varn stepn))))

do* is exactly like do except that the bindings and steppings of the variables are performed sequentially rather than in parallel. It is as if, in the above explanation, let were replaced by let* and psetq were replaced by setq.

 

LISP: DOCUMENTATION

C: Ldocumentation

min args: 2

max args: 2

[F][CLTL 25]

SYNOPSIS:

documentation symbol doc-type

DESCRIPTION:

This function returns the documentation string of type doc-type for the symbol or nil if none exists. The following Star Sapphire Common LISP constructs allow the user to specify a documentation string:

Construct

Documentation Type

defvar

variable

defparameter

variable

defconstant

variable

defun

function

defmacro

function

defstruct

structure

defsetf

setf

The defsetf for documentation, as defined in init0.lsp is:

(defsetf documentation (s d) (v) `(set-documentation ,s ,d ,v))

SEE ALSO:

set-documentation

 

LISP: DOLIST

C: SFCDotl, EDoList

[M][CLTL 7]

SYNOPSIS:

dolist (var listform [resultform]) {declaration}* {tag | statement}*

DESCRIPTION:

dolist provides straightforward iteration over the elements of a list. First dolist evaluates the form listform, which should produce a list. It then executes the body once for each element in the list, in order, with the variable var bound to the element. Then resultform (a single form, not an implicit progn) is evaluated, and the result is the value of the dolist form. (When the resultform is evaluated, the control variable var is still bound, and has the value nil.) If resultform is omitted, the result is nil.

(dolist (x '(a b c d)) (prin1 x) (princ " ")) => nil

after printing "a b c d"

An explicit return statement may be used to terminate the loop and return a specified value.

NOTES:

See dotimes

LISP: DOTIMES

C: SFCDotl, EDoTimes

[M][CLTL 7]

SYNOPSIS

dotimes (var countform [resultform]) {declaration}* {tag | statement}*

DESCRIPTION:

dotimes provides straightforward iteration over a sequence of integers. The expression (dotimes (var countform resultform) . progbody) evaluates the form countform, which should produce an integer. It then performs progbody once for each integer from zero (inclusive) to count (exclusive), in order, with the variable var bound to the integer; if the value of countform is zero or negative, then the prog body is performed zero times. Finally, resultform (a single form, not an implicit progn) is evaluated, and the result is the value of the dotimes form. (When the resultform is evaluated, the control variable var is still bound, and has as its value the number of times the body was executed.) If resultform is omitted, the result is nil.

An explicit return statement may be used to terminate the loop and return a specified value.

Here is an example of the use of dotimes in processing strings:

;;; True if the specified subsequence of the string is a

;;; palindrome (reads the same forwards and backwards).

(defun palindromep (string &optional

(start 0)

(end (length string)))

(dotimes (k (floor (- end start) 2) t)

(unless (char-equal (char string (+ start k))

(char string (- end k 1)))

(return nil))))

(palindromep "Able was I ere I saw Elba") => t

(palindromep "A man, a plan, a canal--Panama!") => nil

Altering the value of var in the body of the loop (by using setq, for example) will have unpredictable, possibly implementation-dependent results. A Common LISP compiler may choose to issue a warning if such a variable appears in a setq.

NOTES:

In the interests of efficiency, in Star Sapphire, the count and iterator in dotimes must be a non-negative non-bignum integer less than the largest C signed long (roughly 2 billion).

Both dolist and dotimes perform a body of statements repeatedly. On each iteration a specified variable is bound to an element of interest that the body may examine. dolist examines successive elements of a list, and dotimes examines integers from 0 to n-1 for some specified positive integer n.

The value of any of these constructs may be specified by an optional result form, which if omitted defaults to the value nil.

The return statement may be used to return immediately from a dolist or dotimes form, discarding any following iterations that might have been performed; in effect, a block named nil surrounds the construct. The body of the loop is implicitly a tagbody construct; it may contain tags to serve as the targets of go statements. Declarations may appear before the body of the loop.

LISP: DOUBLE-FLOAT

[Typespec][CLTL 4]

SYNOPSIS:

double-float [[low] high]

double-float

DESCRIPTION:

This is the type specifier symbol which indicates the set of double precision floating point numbers. Objects of this type are a subtypeof the type float.

This specifier can occur either as a symbol or at the head of a type specifier list. In the latter case, optional low and high values can be specified. The low and high values can be specified as

· a floating point number, indicating an inclusive limit

· a list of exactly one floating point number,indicating

· an exclusive limit

or left unspecified either explicitly by writing * or by omission. If the limit is unspecified it is considered to be negative or positive infinity, for the low and high values respectively.

NOTES:

In this implementaion, there is only one size of floating point number, so use of double-float is equivalent to the use of float.

 

LISP: DRIBBLE

C: Ldribble

min args: 0

max args: 1

[F][CLTL 25]

SYNOPSIS:

dribble &optional filename

DESCRIPTION:

When dribble is called, all characters displayed on the screen or typed in at the LISP: prompt will be captured in the specified file.

All debug output, particularly trace, etc. will be captured, which is the primary use of this function.

When starting a dribble session, dribble takes one argument, a file name.

If the file exists, you will be prompted as to whether you want it overwritten or appended to. Be sure that the file you have specified does not contain anything valuable if you want to overwrite it.

If the file does not exist it will be created.

Exiting LISP voluntarily or invoking dribble with no arguments closes the dribble file and flushes all pending output. The dribble file is buffered, so if the system crashes or LISP exits unexpectedly, not all output may be captured.

Only one dribble file can be active at any given time.

NOTES:

If you use the history mechanism to edit previous lines or edit the current line, the names of the editing keys will appear by name surrounded by wavy brackets in the output. The final version of the line is printed with the annotation {EDITED}.

Star Sapphire has an implementation specific safeguard to avoid overwriting lisp source files. If the file exists and has the suffix .lsp, .lis, .cl or .l, a prompt will ask you whether you really want to dribble over it.