librep
is distributed under the terms of the GNU General Public
License, this basically means that you can give it to anyone for any
price as long as full source code is included; you also have the right
to distribute modified copies in the same way. For the actual legalese
see the file COPYING
in the distribution (or
see (emacs)Copying).
In case it isn't obvious, scripts written to use librep are not considered derived works, and therefore may be licensed however the author wishes. However, the ability of scripts to dynamically load external libraries may complicate this situation.
The distribution includes the following code from other packages:
regexp
implementation, with many modifications.
This is distributed under the terms of his copyright, see the file
src/README.regexp
in the distribution.
sdbm
database library by Ozan Yigit.
gettext
implementation for internationalized message
catalogues.
Be aware that there is absolutely NO WARRANTY for this program, you use it at your own risk. Obviously I hope there are no bugs, but I make no promises regarding the reliability of this software.
librep
is a dialect of Lisp, designed to be used both as an
extension language for applications, and for use as a general
programming language. It was originally written to be mostly-compatible
with Emacs Lisp, but has subsequently diverged markedly. Its aim is to
combine the best features of Scheme and Common Lisp and provide an
environment that is comfortable for implementing both small and large
scale systems. It tries to be a "pragmatic" programming language.
The author has used librep
in its various forms in many projects
since 1993. This includes two large programs which use it as an
extension language, and many stand-alone programs.
rep
stands for "Read, Eval, Print", the three main components of
any Lisp system.
Some of the features of librep
are:
nil
. Instead there is a special object ()
fulfulling
these two roles. For modules importing the rep
module, the
symbol nil
evaluates to ()
. This allows the scheme
module to be more compliant with the Scheme standard
&optional
and &rest
, in favour of
#!optional
and #!rest
.
#!key
to declare them.
Keyword syntax is #:param
. For example:
((lambda (#!key a b) (list a b)) #:b 2 #:a 1) => (1 2)
#!optional
and #!key
parameters may now have
default values, syntax is (var default)
. For
example:
((lambda (#!optional (a 1)) a)) => 1
.
characters in
module names denote directory separators, e.g. foo.bar
translates to the file foo/bar
All module names prefixed with rep.
are reserved for librep,
other top-level names should be picked to be as unique as possible
The existing modules have been renamed to fit this scheme (see the file
TREE
in the distribution for the hierarchy details). However,
old module names will still work for the time being
letrec
expressions
unscheme
module. Another Scheme implementation,
but the goal of this one is to integrate cleanly with the librep
runtime environment, even if this is at the expense of R4RS compliance
For example, in unscheme
code, #f => ()
and
#t => t
. This allows rep and unscheme functions to call
each other without needing to convert any data
define-structures
to export multiple views of a
single underlying environment
--help
option
itself, this should be done by scripts
$LD_LIBRARY_PATH
for plugins, but prepend all
directories in colon-separated $REP_DL_LOAD_PATH
to
dl-load-path
. Similarly, the contents of $REP_LOAD_PATH
is prepended to rep-load-path
(/ x) => (/ 1 x)
#f
and #t
are now primitive symbols, not special
objects
apply
, to ensure they
get eliminated
0x123
and 0123
read syntaxes have been
deprecated, use #x123
and #o123
instead
#| ... |#
comments now nest correctly
rep.i18n.gettext
,
rep.vm.safe-interpreter
, rep.vm.assembler
,
unscheme
, rep.data.objects
, rep.www.quote-url
,
rep.www.fetch-url
, rep.util.ispell
,
rep.util.base64
, rep.util.autoloader
long long
type on AIX, IRIX and Solaris (Dan
McNichol, Albert Chin-A-Young)
DEFUN
macro for C++ (Matt Tucker); also fixed header
files to avoid C++ keywords
default-boundp
, continuation-callable-p
defvar
forms if the symbol
isn't already bound
case
expressions correctly; eliminate
tail-recursion in cond
forms when possible
scheme
module
--without-gmp
option to
configure. Use long long
for non-fixnum integers (promote to
floats when out of range); no exact rationals. There's also an option
to disable continuations/threading (--disable-continuations
)
(declare (inline names...))
to tell the
compiler that it might be useful to inline the named functions
gaol
module. Interface is essentially:
gaol-define
, gaol-define-special
,
gaol-define-file-handler
. Added gaol-open
to import
complete modules. Still supports old interface
thread-join
, waits for a specified thread to
exit, then returns the value of the last form it evaluated
,profile form
command
in repl)
ring
module, sanitized the interface
(preserving compatibility with old functions), also added a
ring->list
function
rplaca
and rplacd
(but not setcar
and
setcdr
) functions now return the cell being modified, not the
value being stored into it, for compatibility with CL (Karl Hegbloom)
unwind-protect
, catch
, condition-case
: these
special forms are now macros
bad-arg
or missing-arg
errors,
try to include the function as the first element of the error data
load
function now only loads files without suffixes
if no-suffix arg is non-nil
(prevents picking up
un-suffixed files by mistake, e.g. from the current directory)
gettext
module not redefining _
binding in rep
module
rep-config
script (Mark Hewitt,
Dan Winship)
rep_INTERN_SPECIAL
macro not looking for
default values of special variables
min
and max
when
operating on non-numeric values
define
forms
load
empty files
gaol
module can now create multiple gaols, each with
it's own namespace
defconst
never evaluates its constant)
Modelled after the Scheme48 system, but simpler. At its simplest,
include a define-structure
form in each file representing a
module:
(define-structure name interface config body...)
The external definitions of this module can then be imported by other
modules through their config statements, e.g. (open
NAMES...)
. Most modules will open rep
to get the
standard language definitions.
foo#bar
reads as (structure-ref foo bar)
The timers
, tables
, sdbm
, gdbm
,
readline
, gettext
, ring
, mutex
,
memoize
, lisp-doc
, disassembler
, compiler
,
date
, cgi-get
, gaol
features are all now modules
(this is backwards compatible, since modules may be imported using
require
)
See the "Modules" section of the manual for more details.
make-datum
, datum-ref
, datum-set
,
has-type-p
, define-datum-printer
define-record-type
macro for
defining data structures (the records
module)
make-fluid
, fluid
, fluid-set
, with-fluids
,
let-fluids
)
queues
module providing a basic queue type
peek-char
, input-stream-p
,
output-stream-p
min
, max
, floor
,
ceiling
, round
, truncate
)
eql
and equal
no longer ignore exactness when
comparing numbers. =
, /=
, <
, >
, <=
and >=
do ignore inexactness. E.g.
(eql 2 2.) => nil (= 2 2.) => t
#b
,
#o
, #d
, #x
radix prefixes, and #e
,
#i
exactness prefixes).
string->number
and
number->string
functions
scheme
). Do ,new foo <RET> ,open scheme to test it in
the repl, use (open scheme)
instead of (open rep)
to use
it within modules.
The compiler also knows enough about Scheme to be able to compile it.
Also, use the -s
or --scheme
options to load a file of
Scheme code.
append
and nconc
may be a
non-proper-list now
do
macro for iteration
define
supports curried functions. E.g. (define
((plus a) b) (+ a b))
, then (plus 1)
evaluates to the function
that adds one to its argument.
(declare clauses...)
form. See the
"Compiler Declarations" section of the manual for details on the
actual declarations supported.
progn
and begin
forms
themselves into the top-level (for when macros expand into multiple
definitions)
(let () ...)
as a named let
let
, let*
,
function
, if
, and
, or
, prog2
,
defmacro
, defun
, defconst
, define-value
,
setq-default
let
now supports Scheme's named-let construct for
iteration via tail recursion
#|
... |#
block comments, #\c
or #\name
characters (where name may be one of: space
,
newline
, backspace
, tab
, linefeed
,
return
, page
, rubout
), and #(...)
vectors
dynamic-wind
function
RTLD_GLOBAL
; everything should
work on Tru64 now (Aron Griffis)
make-guardian
function (as described in Dybvig's paper). These are a clean mechanism
for allowing the programmer to control when arbitrary lisp objects are
finally deallocated. Also added a new hook: after-gc-hook
error-handler-function
contains a function then it will be
called to handle the error, with arguments (error
data)
.
case
, switches on a key value and sets of
constants
call/cc
(also available through the alias
call-with-current-continuation
). Provides scheme-like
continuation functions. Special variables are now deep-bound to support
this correctly
(lambda (x . y) ...)
define
syntax, with support for
inner definitions
tables
plugin implements hash tables, with extensible
hashing and comparison methods; supports both strongly and weakly keyed
tables
put
and get
functions now use equal
to
compare property names
Compiled lisp code will need to be rebuilt to run on the modified virtual machine.
macro-environment
to the
macro environment it was called with. This allows macros to reliably
expand inner macro uses
before-exit-hook
. Called immediately before
exiting
rep-xgettext
now has an option --c
. This makes it
output pseudo C code containing the string constants found
foo//bar
as /bar
. Contiguous path
separators are now merged (i.e. foo/bar
)
.la
files may now contain rep-specific settings:
rep_open_globally=yes
and
rep_requires='FEATURES...'
define-value
. A combination of set
and
defvar
, but without implying dynamic scope
load
scans after-load-alist for plugins as well as
lisp libraries
(if t)
now evaluates to nil
not t
rep_load_environment
and
rep_top_level_exit
defvar
allows symbols to be redefined in protected
environments if they haven't also been defined by unprotected
environments
__builtin_return_address
functions (George Lebl)
gettext
implementation, but only if it
looks like it's the GNU implementation
--with-readline
option)
letrec
, caar
, ..., cddr
,
caaar
, ..., cdddr
, in-hook-p
,
make-variable-special
unless
to have the Common Lisp semantics--return
nil
when the condition evaluates true, not the value of the
condition
rep-xgettext
script to remove duplicated strings and
to search exhaustively
add-hook
forces the hook variable to be special (in case
it wasn't declared using defvar
)
Fixed some documentation bugs; fixed some build problems
defvar
are dynamically scoped.
fset
,
symbol-function
and fboundp
functions have been removed
This allows all elements in procedure-call forms to be evaluated equally (as in scheme), so things like:
((if t + -) 1 2)
now work. Related to this, function names (i.e. symbols and lambda expressions) are no longer dereferenced by any operations taking functions as arguments. Only built-in subroutines and closures are considered functions.
This means that where before you'd write something like:
(mapcar '+ '(1 2 3))
this is now illegal; the +
function must be evaluated:
(mapcar + '(1 2 3))
lambda
is now a special form evaluating to a closure (as
in scheme); this means that the following are exactly equivalent:
(lambda (x) x) == (function (lambda (x) x)) == #'(lambda (x) x)
An alternative method of enclosing a lambda expression is to use the
make-closure
function.
gaol
module providing semi-safe environment for untrusted
code to evaluate in
gettext
module; also support for
%1$s
type format specifiers
string-equal
and string-lessp
--with-rep-prefix
option to autoconf AM_PATH_REP
macro
foo.tar.gz#tar/bar
process-id
function now returns pid of lisp interpreter
when called with zero arguments
shl_load
(HP-UX)
last
function
load
function
autoload-verbose
variable; set it to nil
to
turn off the messages when autoloading
--prefix
option has a trailing slash
No new features; minor portability tweaks and build changes. Fix bug of trying to load directories as Lisp scripts
unsetenv
function
system
now uses process-environment
set-input-handler
, registers an asynchronous
input handler for a local file
SIGCHLD
signals
rep
binary by default always loads a script named
rep
, not named by it's argv[0]
(this breaks under the
newer libtool)
SIGUSR2
prints all debug buffers
--with-value-type
, and
--with-malloc-alignment
configure options. Also added code to
automatically detect the first of these options.
--write-docs
error-mode
and interrupt-mode
control
where errors and user-interrupts (i.e. SIGINT
signals) are
handled. The three possible values are: top-level
, exit
and nil
(denotes the current event loop).
symbolp
.
SIGINT
, SIGHUP
and SIGTERM
signals should
now be caught more successfully.
dl-load-path
:
libexecdir/rep/arch
to contain third-party shared
libraries.
First public release.
The rep
program may be used to launch the stand-alone
librep
environment:
usage: rep [rep-options...] [script [script-options...]]
Where rep-options may be any of the following:
--init file
init.jl
.
--version
--batch
--interp
--no-rc
~/.reprc
script, or the
site-init.jl
script
-f function
-l script
(load "script")
.
-q
If script is given, it names the Lisp file to load, equivalent to
the -l
option, except that --batch-mode
is implied. Any
script-options will be made available to the script (in the
command-line-args
variable).
After any arguments have been processed a banner message will be
displayed before entering an interactive read-eval-print loop, unless
--batch-mode
was specified, in which case the interpreter exits.
The read-eval-print loop simply reads complete Lisp forms (see The Lisp Reader), evaluates them, before printing the result back to the console; this continues ad infinitum, or until you force an EOF (i.e. enter C-d).
rep
ScriptsThe rep
interpreter also supports automatic invocation of
scripts, using the oeprating system's support for #!
interpreter
invocation (i.e. if the first line of an executable text file contains
#! prog
, the program prog is used to execute the
script.
However there is a problem with this method, in that the PATH
environment variable is not searched for the location of the
interpreter, and thus the full file name of the interpreter program
must be hard-coded into the script. To work around this problem
rep
supports a slightly different method of invocation.
If the first two characters of a loaded Lisp file are #!
, then
everything is treated as a comment until the first occurrence of the
string !#
. This allows the first part of the script to be
executed as a shell script invoking the rep
interpreter.
What this means, is that you want to put something like the following at the start of any scripts you want to execute implicitly (and chmod +x the file as well):
#!/bin/sh exec rep "$0" "$@" !# ;; Lisp code follows...
This chapter of the manual is a full guide to the librep Lisp programming language, including documentation for most of the built-in functions.
librep
programming
This manual still fails to document the following functions: default-boundp, default-value, recursive-edit, regexp-cache-control, sdbm-close, sdbm-delete, sdbm-error, sdbm-fetch, sdbm-firstkey, sdbm-nextkey, sdbm-open, sdbm-rdonly, sdbm-store, sdbmp, set-default, setq-default,
As you have probably gathered by now, librep
provides a dialect
of the Lisp programming language--a dialect originally inspired by
Emacs Lisp, but later adapted to include many features from various
Scheme implementations and Common Lisp. The language dialect aims to be
convenient for both extending applications and writing large
stand-alone programs.
All programs written using only the information in this manual should
be compatible with future revisions of librep
.
This following sections explain some of the most important Lisp concepts and the conventions I've used in this manual.
In the rep Lisp dialect there is a single data value representing
boolean "false"--the empty list, written as ()
. All other
values are considered "not-false", i.e. "true".
By convention the constants nil
and t
are used to
represent the canonical boolean values. The constant variable
nil
evaluates to the empty list (i.e. "false"), while t
evaluates to itself (i.e. not-"false", therefore "true").
Reiterating, all of the conditional operations regard anything
which is not ()
as being true (i.e. non-false). The actual
symbol t
should be used where a true boolean value is explicitly
stated, to increase the clarity of the code.
So, ()
, and its alias nil
, represent both the empty list
and boolean falsehood. Most Lisp programmers write ()
where its
value as a list should be emphasized, and nil
where its value as
boolean false is intended. Although neither of these values need be
quoted (see Quoting), most programmers will quote the empty list to
emphasize that it is a constant value. However nil
should not be
quoted, doing so would produce the symbol nil
, not
boolean falsehood. For example:
(append '() '()) => () ;Emphasize use of empty lists
(not nil) => t ;Emphasize use as boolean false
(get 'nil 'color) ;Use the symbol nil
When a function is said to "return false", it means that it returns the false boolean value, i.e. the empty list. When a function is said to "return true", this means that any non-false value is returned.
Lisp programs and functions are stored internally as Lisp data objects, the Lisp Reader is the mechanism that translates from textual descriptions of Lisp objects to the internal data structures representing them.
The Lisp Reader is the collection of internal functions accessed by the
read
Lisp function. It reads a character at a time from an input
stream until a whole Lisp object has been parsed.
See Data Types.
Wherever an example of evaluating a Lisp form is shown it will be formatted like this,
(+ 1 2) => 3
The glyph =>
is used to show the computed value of a
form. 1
When two forms are shown as being exactly equivalent to one another the
glyph ==
is used, for example,
(car some-variable) == (nth 0 some-variable)
Evaluating some forms result in an error being signalled, this is denoted
by the error-->
glyph.
(open-file "/tmp/foo" 'read) error--> File error: No such file or directory, /tmp/foo
In this document the simplest type of descriptions are those defining variables (see Variables), they look something like:
grains-of-sand | Variable |
This imaginary variable contains the number of grains of sand in a one-mile long stretch of an averagely sandy beach. |
Hooks (see Hooks) are also described in this format, the only
difference is that Variable:
is replaced by Hook:
.
Functions (see Functions) and macros (see Macros) have more complex descriptions; as well as the name of the object being described, they also have a list of parameters which the object will accept. Each parameter in the list is named and may be referred to in the body of the description.
Three keyword parameters may also be used: #!optional
,
#!key
and #!rest
. They have the same meaning as when used
in the lambda-list of a function definition (see Lambda Expressions). That is, #!optional
means that all further
parameters are optional, and #!rest
means that the following
parameter actually receives a list of any unused argument values.
An example function definition follows.
useless-function first #!optional second #!rest tail | Function |
This function returns a list consisting of the values second (when
undefined the number 42 is used), all the items in the list tail
and first.
(useless-function 'foo 'bar 'xyz 20) => (bar xyz 20 foo) (useless-function '50) => (42 50) |
Macros and interactive commands are defined in the same way with
Macro:
or Command:
replacing Function:
.
Special forms (see Special Forms) are described similarly to
functions except that the argument list is formatted differently, since
special forms are, by definition, more flexible in how they treat their
arguments. Optional values are enclosed in square brackets
([optional-arg]
) and three dots
(repeated-arg...
) indicate where zero or more
arguments are allowed.
The way that data is represented in Lisp is fundamentally different to languages such as C or Fortran. In Lisp each piece of data (or value) has two basic attributes: the data and the type of the data. This means that type checking is performed at run-time on the actual data itself, not at compile-time on the "variable" holding the data.
Also, there are no "pointers" in Lisp. As in the Java programming language, all values are references to data structures, with each actual data structure (or Lisp Object) being able to have as many values referring to it concurrently as necessary. Because of this lack of pointers, there can be no memory-leakage in Lisp--when an object has no more extant references, it is automatically deallocated (see Garbage Collection).
Most Lisp objects are a member of one of the primitive types; these are types built into the Lisp system and can represent things like strings, numbers, cons cells, vectors, etc... Other primitive types may be defined at run-time.
More complex objects may be constructed from these primitive types, for
example a vector of three elements could be regarded as a type
triple
if necessary. In general, each separate type provides a
predicate function which returns true when applied to an object of
its own type.
Finally, one of the most important differences between Lisp and other languages is that there is no distinction between programs and data. But this will be explained later.
Each separate data type is documented in its own section, this is a just a summary of the more common types.
()
, which is the empty list,
or false truth value.
As previously noted the Lisp reader translates textual descriptions of Lisp objects into the object they describe (source files are simply descriptions of objects). However, not all data types can be created in this way: in fact the only types which can are numbers, strings, symbols, cons cells (or lists) and vectors, all others have to be created by calling functions.
Single line comments are introduced by a semi-colon character
(;
). Whenever the Lisp reader encounters a semi-colon where it's
looking for the read syntax of a new Lisp object it will discard the
rest of the line of input. Block comments are also supported,
introduced by the string #|
and terminated by |#
.
See Comment Styles.
The read syntax of an object is the string which when given to the reader as input will produce the object. The read syntax of each type of object is documented in that type's main section of this manual but here is a small summary of how to write each type.
#o
) or hexadecimal (when the number is
preceded by #x
)--or a decimal rational or floating point value.
An optional minus sign may be the first character in a number. Some
examples are,
42 => 42 #o177 => 127 #x-ff => -255 3/2 => 3/2 1.23 => 1.23
"
) at each end, for more details see Strings.
"This is a string"
("car" . "cdr")
(0 1 2 3) ("foo" ("bar" "baz") 100)
The second example is a list of three elements, a string, an inner list
and a number.
[0 1 2 3]
my-symbol
is,
my-symbol
As well as translating textual descriptions to Lisp objects, the process may be reversed, converting a value back to a textual description. The resulting text is known as the printed representation of the object, and will usually be very similar to the read syntax of the object (see Read Syntax).
Objects which do not have a read syntax do have a printed representation, it will normally be of the form,
#<relevant-text>
where the relevant-text is object-dependent and usually describes
the object and its contents. The reader will signal an error if it
encounters a description of an object in the format #<...>
.
eq arg1 arg2 | Function |
Returns true when arg1 and arg2 refer to the same object.
Two objects are the same when they occupy the same place in memory and
hence modifying one object would alter the other. The following Lisp
fragments may illustrate this,
(eq "foo" "foo") ;the objects are distinct
=> ()
(eq t t) ;the same object -- the symbol
Note that the result of |
equal arg1 arg2 | Function |
The function equal compares the structure of the two objects
arg1 and arg2. If they are considered to be equivalent then
returns true, otherwise returns false.
(equal "foo" "foo") => t (equal 42 42) => t (equal 42 0) => () (equal '(x . y) '(x . y)) => t |
eql arg1 arg2 | Function |
This function is a cross between eq and equal : if
arg1 and arg2 are both numbers then the value of these
numbers are compared. Otherwise it behaves in exactly the same manner
as eq does.
(eql 3 3) => t (eql 1 2) => () (eql "foo" "foo") => () (eql 'x 'x) => t |
These functions compare their two arguments in a scalar fashion, the arguments may be of any type but the results are only meaningful for numbers, strings (ASCII values of each byte compared until a non-matching pair is found then those two values are compared as numbers) and cons cells (cars compared before cdrs).
Unlike the eql
function, inexact and exact numbers will be
compared by first coercing the exact number to be inexact.
= arg1 arg2 arg3 ... argn | Function |
Returns true if all arguments represent the same value. |
/= arg1 arg2 arg3 ... argn | Function |
Returns true if no two arguments represent the same value. |
> arg1 arg2 arg3 ... argn | Function |
Returns true when arg1 is `greater than' arg2, and arg2 is greater than arg3, and so on, upto argn. |
>= arg1 arg2 arg3 ... argn | Function |
Similar to > , but for the "greater than or equal to" relation.
|
< arg1 arg2 arg3 ... argn | Function |
Similar to > , but for the "less than" relation.
|
<= arg1 arg2 arg3 ... argn | Function |
Similar to > , but for the "less than or equal to" relation.
|
There are two related functions for finding the maximum or minimum of a sequence of values.
max #!rest args | Function |
Return the maximum value from the list of args. When comparing numbers, any inexact arguments cause the result to be inexact. |
min #!rest args | Function |
Return the minimum value from the list of args. When comparing numbers, any inexact arguments cause the result to be inexact. |
Each type has a corresponding predicate which defines the objects which are members of that type. Each predicate function has a single parameter, if that parameter is of the correct type it returns true.
integerp
, numberp
, null
, consp
,
listp
, vectorp
, subrp
, functionp
,
sequencep
, stringp
, symbolp
, processp
,
filep
.
The documentation for these functions is with the documentation for the relevant type.
In Lisp, data objects are used very freely; a side effect of this is that it is not possible to (easily) know when an object is stale, that is, no references to it exist and it can therefore be reused.
The garbage collector is used to overcome this problem; whenever enough memory has been allocated to make it worthwhile, evaluation stops and the garbage collector works its way through memory deciding which objects may still be referenced, and which are stale. The stale objects are then recorded as being available for reuse and evaluation continues. (But see Guardians)
garbage-collect | Function |
Runs the garbage collector, usually this function doesn't need to be called manually. |
garbage-threshold | Variable |
The number of bytes of data that must have been allocated since the last garbage collection before evaluation pauses and the garbage collector is invoked. Its default value is about 100K. |
idle-garbage-threshold | Variable |
When the input loop is idle (due to a lack of input), this is the
number of bytes of data that must have been allocated since the garbage
collection, for another collection to be triggered.
This is usually set to a lot less than |
after-gc-hook | Variable |
A hook (see Normal Hooks) called immediately after each invocation of the garbage collector. |
Librep
distinguishes between numbers that are represented
exactly and numbers that may not be. This is similar to the Scheme
dialect of Lisp. Quoting from the Scheme standard:
... numbers are either exact or inexact. A number is exact if it was written as an exact constant or was derived from exact numbers using only exact operations. A number is inexact if it was written as an inexact constant, if it was derived using inexact ingredients, or if it was derived using inexact operations. Thus inexactness is a contagious property of a number.
Exact numbers include both integers and rational numbers, there is no theoretical limit to the range of the values that may be represented 2. Inexact numbers are currently implemented using double precision floating point values.
The read syntax of any number is:
[pfx...][sgn]data...
, where the
optional sgn is one of the characters -
or +
,
data is the representation of the number, and pfx is zero
or more of the following prefix strings:
#b
#B
#o
#O
#d
#D
#x
#X
#e
#E
#i
#I
The representation of an integer is simply the digits representing that
integer, in the radix chosen by any given prefix (defaults to decimal).
Examples of valid integer read syntaxes for the number 42 could be
42
, #x2a
, #o52
, #o+52
, ...
The representation of a rational number is two sequences of digits,
separated by a /
character. For example, 3/2
represents
the rational number three divided by two.
Inexact numbers are parsed from one of two representations: decimal
point form, which is simply a decimal number containing a decimal
point, and exponential form, which is a decimal number followed by the
letter e
and a decimal exponent multiplying the first part of
the number by that power of ten. For example, 10.0
, 10.
and 1e1
all read as the inexact number ten. Note that the radix
prefixes currently have no effect when parsing inexact numbers, decimal
is used exclusively.
An integer's printed representation is simply the number printed in
decimal with a preceding minus sign if it is negative. Rational numbers
are printed as two integers separated by a /
character. Inexact
numbers are printed in their decimal form.
numberp object | Function |
Returns true if object is a number. |
There are a number of functions which perform arithmetic operations on numbers, they take a varying number of values as their arguments returning a new number as their result. When given only exact arguments, an exact result will be returned.
+ number1 #!rest numbers | Function |
This functions adds its arguments then returns their sum. |
- number1 #!rest numbers | Function |
If this function is just given one argument (number1) that number is
negated and returned. Otherwise each of numbers is subtracted from
a running total starting with the value of number1.
(- 20) => -20 (- 20 10 5) => 5 |
* number1 #!rest numbers | Function |
This function multiplies its arguments then returns the result. |
/ number1 #!rest numbers | Function |
This function performs division, a running-total (initialised from
number1 is successively divided by each of numbers then
the result is returned.
(/ 100 2) => 50 (/ 200 2 5) => 20 (/ 3 2) => 3/2 (/ 3.0 2) => 1.5 |
1+ number | Function |
This function returns the result of adding one to number.
(1+ 42) => 43 |
1- number | Function |
Returns number minus one. |
The functions described in this section all operate on, and return, integer values.
quotient dividend divisor | Function |
Return the integer part of dividing dividend by divisor. |
remainder dividend divisor | Function |
Returns the integer remainder from dividing the dividend by divisor. The remainder is either zero or has the same sign as dividend. |
modulo dividend divisor | Function |
mod dividend divisor | Function |
Return the value of dividend modulo divisor. Unlike the
remainder function the modulo function always has the
sign of the divisor, not of the dividend
|
gcd args... | Function |
Returns the greatest common divisor of the integers args... If no arguments are given, returns zero. |
lcm args... | Function |
Return the lowest common multiple of the integers args... If no arguments are given, returns one. |
These functions operate on rational numbers.
numerator x | Function |
Returns the exact numerator of x. |
denominator x | Function |
Returns the exact denominator of x. |
exact->inexact x | Function |
Returns an inexact version of rational number x. |
abs x | Function |
Returns the magnitude of x. |
floor x | Function |
Round x downwards to the nearest integer less than or equal to x. |
ceiling x | Function |
Round x upwards to the nearest integer less than or equal to x. |
truncate x | Function |
Round x to the nearest integer between x and zero. |
round x | Function |
Round x to the nearest integer. Halfway cases are rounded to the nearest even integer. |
inexact->exact x | Function |
Returns an exact representation of x. This may involve a loss of accuracy. |
exp x | Function |
Return `e' (the base of natural logarithms) raised to the power x. |
log x | Function |
Return the natural logarithm of x. An arithmetic error is signalled if x is less than zero. |
sin x | Function |
Return the sine of angle x; x is in terms of radians. |
cos x | Function |
Return the cosine of angle x. |
tan x | Function |
Return the tangent of angle x. |
asin x | Function |
Return the arc sine of x (the value whose sine is x), in radians. |
acos x | Function |
Return the arc cosine of x. |
atan x | Function |
Return the arc tangent of x. |
sqrt x | Function |
Return the non-negative square root of x. Currently, if x is negative, an arithmetic error is signalled. |
expt x y | Function |
Returns x raised to the power y.
If x is negative and y is a non-integer, then an arithmetic error is signalled (mathematically should return a complex number). |
These functions operate on the bit string which an integer represents, assuming a two's complement representation.
lsh number count | Function |
This function shifts the integer number count bits to the
left, if count is negative number is shifted to the right
instead.
(lsh 1 8) => 256 (lsh 256 -8) => 1 |
logand number1 #!rest numbers | Function |
This function uses a bit-wise logical `and' operation to combine all its
arguments (there must be at least one argument).
(logand 15 8) => 8 (logand 15 7 20) => 4 |
logior number1 #!rest numbers | Function |
Uses a bit-wise logical `inclusive-or' to combine all its arguments (there
must always be at least one argument).
(logior 1 2 4) => 7 |
logxor number1 #!rest numbers | Function |
Uses a bitwise logical `exclusive-or' to combine all its arguments
(there must be at least one).
(logxor 7 3) => 4 |
lognot number | Function |
This function inverts all the bits in number.
(lognot 0) => -1 (lognot 2) => -3 (lognot -1) => 0 |
For the documentation of the functions =
, /=
, >
,
<
, >=
, <=
, max
and min
, see
Comparison Predicates.
exactp object | Function |
Returns true when object is an exact number. |
inexactp object | Function |
Returns true when object is an inexact number. |
integerp object | Function |
Returns true when object is an integer. |
rationalp object | Function |
Returns true when object is a rational number (including integers). |
realp object | Function |
Returns true when object is a real number. |
oddp x | Function |
Return true if x is an odd number. |
evenp x | Function |
Return true if x is an even number. |
positivep x | Function |
Return true if x is a number greater than zero. |
negativep x | Function |
Return true if x is a number less than zero. |
zerop x | Function |
Returns true if x is equal to zero. |
The random
function allows pseudo-random numbers to be
generated.
random #!optional limit | Function |
Return a pseudo-random number between zero and limit-1 inclusive.
If limit is undefined, it is taken as being the largest positive
integer representable in a fixnum.
Calling |
In librep
characters are stored in integers. Their read syntax
is a question mark followed by the character itself, which may be an
escape sequence introduced by a backslash. For details of the available
escape sequences see Strings.
?a => 97 ?\n => 10 ?\177 => 127
alpha-char-p character | Function |
This function returns true when character is one of the
alphabetic characters.
(alpha-char-p ?a) => t |
upper-case-p character | Function |
When character is one of the upper-case characters this function returns true. |
lower-case-p character | Function |
Returns true when character is lower-case. |
digit-char-p character | Function |
This function returns true when character is one of the decimal digit characters. |
alphanumericp character | Function |
This function returns true when character is either an alphabetic character or a decimal digit character. |
space-char-p character | Function |
Returns true when character is a white-space character (space, tab, newline or form feed). |
char-upcase character | Function |
This function returns the upper-case equivalent of character. If
character is already upper-case or has no upper-case equivalent it
is returned unchanged.
(char-upcase ?a) => 65 ;`A' (char-upcase ?A) => 65 ;`A' (char-upcase ?!) => 33 ;`!' |
char-downcase character | Function |
Returns the lower-case equivalent of the character character. |
Sequences are ordered groups of objects, there are several primitive types which can be considered sequences, each with their pros and cons.
A sequence is either an array or a list, where an array is either a vector or a string.
sequencep object | Function |
This function returns true if object is a sequence. |
A cons cell is an ordered pair of two objects, the car and the cdr.
The read syntax of a cons cell is an opening parenthesis followed by the
read syntax of the car, a dot, the read syntax of the cdr and a closing
parenthesis. For example a cons cell with a car of 10 and a cdr of
the string foo
would be written as,
(10 . "foo")
cons car cdr | Function |
This function creates a new cons cell. It will have a car of car and
a cdr of cdr.
(cons 10 "foo") => (10 . "foo") |
consp object | Function |
This function returns true if object is a cons cell.
(consp '(1 . 2)) => t (consp '()) => () (consp (cons 1 2)) => t |
The strange syntax '(1 . 2)
is known as quoting
(see Quoting), it tells the evaluator that the object following the
quote-mark is a constant, and therefore should not be evaluated. This
will be explained in more detail later.
In Lisp an atom is any object which is not a cons cell (and is, therefore, atomic).
atom object | Function |
Returns true if object is an atom (not a cons cell). |
Given a cons cell there are a number of operations which can be performed on it.
car cons-cell | Function |
This function returns the object which is the car (first element) of
the cons cell cons-cell.
(car (cons 1 2)) => 1 (car '(1 . 2)) => 1 |
cdr cons-cell | Function |
This function returns the cdr (second element) of the cons cell
cons-cell.
(cdr (cons 1 2)) => 2 (cdr '(1 . 2)) => 2 |
rplaca cons-cell new-car | Function |
This function sets the value of the car (first element) in the cons
cell cons-cell to new-car. The value returned is
cons-cell.
(setq x (cons 1 2)) => (1 . 2) (rplaca x 3) => (3 . 2) x => (3 . 2) |
rplacd cons-cell new-cdr | Function |
This function is similar to rplacd except that the cdr slot
(second element) of cons-cell is modified.
|
A list is a sequence of zero or more objects, the main difference between lists and vectors is that lists are more dynamic: they can change size, be split, reversed, concatenated, etc... very easily.
In Lisp lists are not a primitive type; instead singly-linked lists are
formed by chaining cons cells together (see Cons Cells). The empty
list is represented by the special value ()
.
listp arg | Function |
This functions returns true when its argument, arg, is a
list (i.e. either a cons cell or () ).
|
null arg | Function |
Returns a true value if arg is the empty list. |
Each element in a list is given its own cons cell and stored in the car
of that cell. The list is then constructed by having the cdr of a cell
point to the cons cell containing the next element (and hence the
entire rest of the list). The cdr of the cell containing the last
element in the list is ()
. A list of zero elements is
represented by ()
.
The read syntax of a list is an opening parenthesis, followed by the read syntax of zero or more space-separated objects, followed by a closing parenthesis. Alternatively, lists can be constructed `manually' using dotted-pair notation.
All of the following examples result in the same list of five elements: the numbers from zero to four.
(0 1 2 3 4) (0 . (1 . (2 . (3 . (4 . ()))))) (0 1 2 . (3 4))
An easy way to visualise lists and how they are constructed is to see each cons cell in the list as a separate box with pointers to its car and cdr,
+-----+-----+ | o | o----> cdr +--|--+-----+ | --> car
Complex box-diagrams can now be drawn to represent lists. For example the
following diagram represents the list (1 2 3 4)
.
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+ | o | o----> | o | o----> | o | o----> | o | o----> () +--|--+-----+ +--|--+-----+ +--|--+-----+ +--|--+-----+ | | | | --> 1 --> 2 --> 3 --> 4
A more complex example, the list ((1 2) (foo bar))
can be drawn as,
+-----+-----+ +-----+-----+ | o | o---------------------------> | o | o----> () +--|--+-----+ +--|--+-----+ | | +-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+ | o | o----> | o | o----> () | o | o----> | o | o----> () +--|--+-----+ +--|--+-----+ +--|--+-----+ +--|--+-----+ | | | | --> 1 --> 2 --> foo --> bar
It has already been described how you can create lists using the Lisp reader; this method does have a drawback though: the list created is effectively static. If you modify the contents of the list and that list was created when a function was defined the list will remain modified for all future invocations of that function. This is not usually a good idea, consider the following function definition,
(defun bogus-function (x) "Return a list whose first element is nil and whose second element is X." (let ((result '(nil nil))) ;Static list which is filled in each time (rplaca (cdr result) x) ; the function is called result))
This function does in fact do what its documentation claims, but a problem arises when it is called more than once,
(setq x (bogus-function 'foo)) => (nil foo) (setq y (bogus-function 'bar)) => (nil bar) ;The first result has been destroyed x => (nil bar) ;See!
This example is totally contrived--no one would ever write a function like the one in the example but it does demonstrate the need for a dynamic method of creating lists.
list #!rest elements | Function |
This function creates a list out of its arguments, if zero arguments are
given the empty list, () , is returned.
(list 1 2 3) => (1 2 3) (list (major-version-number) (minor-version-number)) => (3 2) (list) => () |
list* arg1 arg2 ... argn-1 argn | Function |
Creates a new list (arg1 arg2 ... argn-1 .
argn) .
(list* 1 2 '(3 4)) => (1 2 3 4) |
make-list length #!optional initial-value | Function |
This function creates a list length elements long. If the
initial-value argument is given it defines the value of all
elements in the list, if it is not defined they are all () .
(make-list 2) => (() ()) (make-list 3 t) => (t t t) (make-list 0) => () |
append #!rest lists | Function |
This function creates a new list with the elements of each of its arguments
(which must be lists). Unlike the function nconc this function
preserves the structure of all its arguments.
(append '(1 2 3) '(4 5)) => (1 2 3 4 5) (append) => () What actually happens is that all arguments but the last are copied, then the last argument is linked on to the end of the list (uncopied). (setq foo '(1 2)) => (1 2) (setq bar '(3 4)) => (3 4) (setq baz (append foo bar)) => (1 2 3 4) (eq (nthcdr 2 baz) bar) => t The following diagram shows the final state of the three variables more clearly, foo--> +-----+-----+ +-----+-----+ | o | o----> | o | | +--|--+-----+ +--|--+-----+ | | o--> 1 o--> 2 bar | | -> baz--> +--|--+-----+ +--|--+-----+ +-----+-----+ +-----+-----+ | o | o----> | o | o----> | o | o----> | o | | +-----+-----+ +-----+-----+ +--|--+-----+ +--|--+-----+ | | --> 3 --> 4 Note how |
remove elt list | Function |
Return a copy of list, with all elements the same as elt
discarded (using the equal function to compare).
|
remq elt list | Function |
Similar to the remove function, except that comparisons are made
using eq .
|
reverse list | Function |
This function returns a new list; it is made from the elements of the list
list in reverse order. Note that this function does not alter its
argument.
(reverse '(1 2 3 4)) => (4 3 2 1) |
As a postscript to this section, the function used as an example at the beginning could now be written as,
(defun not-so-bogus-function (x) (list nil x))
Also note that the cons
function can be used to create lists by hand
and to add new elements onto the front of a list. For example:
(setq x (list 1 2 3)) => (1 2 3) (setq x (cons 0 x)) => (0 1 2 3)
The most flexible method of accessing an element in a list is via a
combination of the car
and cdr
functions. There are other
functions which provide an easier way to get at the elements in a flat
list. These will usually be faster than a string of car
and
cdr
operations.
nth count list | Function |
This function returns the element count elements down the list,
therefore to access the first element use a count of zero (or even
better the car function). If there are too few elements in the list
and no element number count can be found () is returned.
(nth 3 '(0 1 2 3 4 5)) => 3 (nth 0 '(foo bar) => foo |
nthcdr count list | Function |
This function takes the cdr of the list list count times,
returning the last cdr taken.
(nthcdr 3 '(0 1 2 3 4 5)) => (3 4 5) (nthcdr 0 '(foo bar)) => (foo bar) |
last list | Function |
This function returns the last element in the list list. If the
list has zero elements () is returned.
(last '(1 2 3)) => 3 (last '()) => () |
member object list | Function |
This function scans through the list list until it finds an element
which is equal to object. The tail of the list (the cons cell
whose car is the matched object) is then returned. If no elements match
object then the empty list () is returned.
(member 'c '(a b c d e)) => (c d e) (member 20 '(1 2)) => () |
memq object list | Function |
This function is similar to member except that comparisons are
performed by the eq function not equal .
|
The nthcdr
function can be used in conjunction with the rplaca
function to modify an arbitrary element in a list. For example,
(rplaca (nthcdr 2 '(0 1 2 3 4 5)) 'foo) => foo
sets the third element of the list (0 1 2 3 4 5)
to the symbol
called foo
.
There are also functions which modify the structure of a whole list. These are called destructive operations because they modify the actual structure of a list--no copy is made. This can lead to unpleasant side effects if care is not taken.
nconc #!rest lists | Function |
This function is the destructive equivalent of the function append ,
it modifies its arguments so that it can return a list which is the
concatenation of the elements in its arguments lists.
Like all the destructive functions this means that the lists given as
arguments are modified (specifically, the cdr of their last cons cell
is made to point to the next list). This can be seen with the
following example (similar to the example in the (setq foo '(1 2)) => (1 2) (setq bar '(3 4)) => (3 4) (setq baz (nconc foo bar)) => (1 2 3 4) foo => (1 2 3 4) ;`foo' has been altered! (eq (nthcdr 2 baz) bar) => t The following diagram shows the final state of the three variables more clearly, foo--> bar--> baz--> +-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+ | o | o----> | o | o----> | o | o----> | o | | +--|--+-----+ +--|--+-----+ +--|--+-----+ +--|--+-----+ | | | | --> 1 --> 2 --> 3 --> 4 |
nreverse list | Function |
This function rearranges the cons cells constituting the list list
so that the elements are in the reverse order to what they were.
(setq foo '(1 2 3)) => (1 2 3) (nreverse foo) => (3 2 1) foo => (1) ;`foo' wasn't updated when the list ; was altered. |
delete object list | Function |
This function destructively removes all elements of the list list
which are equal to object then returns the modified list.
(delete 1 '(0 1 0 1 0)) => (0 0 0) When this function is used to remove an element from a list which is stored
in a variable that variable must be set to the return value of the
(setq foo '(1 2 3)) => (1 2 3) (delete 1 foo) => (2 3) foo => (1 2 3) (setq foo (delete 1 foo)) => (2 3) |
delq object list | Function |
This function is similar to the delete function, the only difference
is that the eq function is used to compare object with each
of the elements in list, instead of the equal function which
is used by delete .
|
sort list #!optional predicate | Function |
Destructively sorts (i.e. by modifying cdrs) the list of values
list, to satisfy the function predicate, returning the
sorted list. If predicate is undefined, the < function is
used, sorting the list into ascending order.
predicate is called with two values, it should return true if the first is considered less than the second. (sort '(5 3 7 4)) => (3 4 5 7) The sort is stable, in that elements in the list which are equal will preserve their original positions in relation to each other. |
An association list (or alist) is a list mapping keys to to. Each element of the alist is a cons cell, the car of which is the key, the cdr the value that it associates to. For example an alist could look like,
((fred . 20) (bill . 30))
this alist has two keys, fred
and bill
which both associate
to an integer (20 and 30 respectively).
It is possible to make the associated values lists, this looks like,
((fred 20 male) (bill 30 male) (sue 25 female))
in this alist the symbol fred
is associated with the list
(20 male)
.
There are a number of functions which let you interrogate an alist with a given key for its association.
assoc key alist | Function |
This function scans the association list alist for the first element
whose car is equal to key, this element is then returned. If
no match of key is found false is returned.
(assoc 'two '((one . 1) (two . 2) (three . 3))) => (two . 2) |
assq key alist | Function |
Similar to the function assoc except that the function eq is
used to compare elements instead of equal .
It is not usually wise to use (assq "foo" '(("bar" . 1) ("foo" . 2))) => () (assoc "foo" '(("bar" . 1) ("foo" . 2))) => ("foo" . 2) |
rassoc association alist | Function |
This function searches through alist until it finds an element whose
cdr is equal to association, that element is then returned.
false will be returned if no elements match.
(rassoc 2 '((one . 1) (two . 2) (three . 3))) => (two . 2) |
rassq association alist | Function |
This function is equivalent to rassoc except that it uses eq
to make comparisons.
|
Sometimes it is useful to be able to create `infinite' lists--that is, lists which appear to have no last element--this can easily be done in Lisp by linking the cdr of the last cons cell in the list structure back to the beginning of the list.
----------------------------------- | | --> +-----+-----+ +-----+-----+ | | o | o----> | o | o----- +--|--+-----+ +--|--+-----+ | | --> 1 --> 2
The diagram above represents the infinite list (1 2 1 2 1 2 ...)
.
Infinite lists have a major drawback though, many of the standard list manipulation functions can not be used on them. These functions work by moving through the list until they reach the end. If the list has no end the function may never terminate and the only option is to send the interpreter an interrupt signal.
The only functions which may be used on circular lists are: the cons
cell primitives (cons
, car
, cdr
, rplaca
,
rplacd
), nth
and nthcdr
.
Also note that infinite lists can't be printed. But note the
print-length
and print-level
variables, see Output Functions.
A vector is a fixed-size sequence of Lisp objects, each element may be accessed in constant time--unlike lists where the time taken to access an element is proportional to the position of the element.
The read syntax of a vector is an opening square bracket, followed by zero or more space-separated objects, followed by a closing square bracket. For example,
[zero one two three]
In general it is best to use vectors when the number of elements to be stored is known and lists when the sequence may grow or shrink.
vectorp object | Function |
This function returns true if its argument, object, is a vector. |
vector #!rest elements | Function |
This function creates a new vector containing the arguments given to the
function.
(vector 1 2 3) => [1 2 3] (vector) => [] |
make-vector size #!optional initial-value | Function |
Returns a new vector, size elements big. If initial-value is
defined each element of the new vector is set to initial-value, otherwise
they are all () .
(make-vector 4) => [() () () ()] (make-vector 2 t) => [t t] |
A string is a vector of characters (see Characters), they are
generally used for storing and manipulating pieces of text.
librep
puts no restrictions on the values which may be stored in
a string--specifically, the null character (^@
) may be
stored with no problems.
The read syntax of a string is a double quote character, followed by the
contents of the string, the object is terminated by a second double quote
character. For example, "abc"
is the read syntax of the string
abc
.
Any backslash characters in the string's read syntax introduce an escape sequence; one or more of the following characters are treated specially to produce the next actual character in the string.
The following escape sequences are supported (all are shown without their
leading backslash \
character).
n
r
f
t
a
\
^c
For example,
\^C ;A Ctrl-c character (ASCII value 3) \^@ ;The NUL character (ASCII value 0)
012
012
. After the
backslash character the Lisp reader reads up to three octal digits and
combines them into one character.
x12
12
, i.e.
an x
character followed by one or two hex digits.
stringp object | Function |
This function returns true if its argument is a string. |
make-string length #!optional initial-character | Function |
Creates a new string containing length characters, each character
is initialised to initial-character (or to spaces if
initial-character is not defined).
(make-string 3) => " " (make-string 2 ?$) => "$$" |
concat #!rest args | Function |
This function concatenates all of its arguments, args, into a single
string which is returned. If no arguments are given then the null string
( ) results.
Each of the args may be a string, a character or a list or vector of characters. Characters are stored in strings modulo 256. (concat "foo" "bar") => "foobar" (concat "a" ?b) => "ab" (concat "foo" [?b ?a ?r]) => "foobar" (concat) => "" |
substring string start #!optional end | Function |
This function creates a new string which is a partial copy of the string
string. The first character copied is start characters from
the beginning of the string. If the end argument is defined it is
the index of the character to stop copying at, if it is not defined
all characters until the end of the string are copied.
(substring "xxyfoozwx" 3 6) => "foo" (substring "xyzfoobar" 3) => "foobar" |
string= string1 string2 | Function |
This function compares the two strings string1 and
string2--if they are made from the same characters in the same
order then true is returned.
(string= "one" "one") => t (string= "one" "two") => () Note that an alternate way to compare strings (or anything!) is to use the
|
string-equal string1 string2 | Function |
Returns true if string1 and string2 are the same, ignoring differences in character case. |
string< string1 string2 | Function |
This function returns true if string1 is `less' than string2 .
This is determined by comparing the two strings a character at a time, the
first pair of characters which do not match each other are then compared
with a normal `less-than' function.
In (string< "abc" "abd") => t (string< "abc" "abb") => () |
string-lessp string1 string2 | Function |
Similar to string< but ignores character case in comparisons.
|
See String Functions for a few more string manipulating functions, and Regular Expressions for a method of pattern matching in strings.
arrayp object | Function |
This function returns true if object is an array. |
aref array position | Function |
Returns the element of the array (vector or string) array position
elements from the first element (i.e. the first element is numbered zero).
If no element exists at position in array, false is
returned.
(aref [0 1 2 3] 2) => 2 (aref "abcdef" 3) => 100 ;`d' |
aset array position value | Function |
This function sets the element of the array array with an index of
position (counting from zero) to value. An error is signalled
if element position does not exist. The result of the function is
value.
(setq x [0 1 2 3]) => [0 1 2 3] (aset x 2 'foo) => foo x => [0 1 foo 3] |
sequencep arg | Function |
Returns true if arg is a sequence, i.e. a list or an array. |
length sequence | Function |
This function returns the length (an integer) of the sequence sequence.
(length "abc") => 3 (length '(1 2 3 4)) => 4 (length [x y]) => 2 |
copy-sequence sequence | Function |
Returns a new copy of the sequence sequence. Where possible (in lists
and vectors) only the `structure' of the sequence is newly allocated: the
same objects are used for the elements in both sequences.
(copy-sequence "xy") => "xy" (setq x '("one" "two")) => ("one" "two") (setq y (copy-sequence x)) => ("one" "two") (eq x y) => () (eq (car x) (car y)) => t |
elt sequence position | Function |
This function returns the element of sequence position elements
from the beginning of the sequence.
This function is a combination of the (elt [0 1 2 3] 1) => 1 (elt '(foo bar) 0) => foo |
Symbols are objects with a name (almost always a unique name). They are one of the most important data types in Lisp since they are used to provided named variables (see Variables) and functions (see Functions).
symbolp arg | Function |
This function returns true when its argument is a symbol. |
The read syntax of a symbol is usually its name; however, if the name
contains any meta-characters (whitespace or any from ()[]'";|\
)
they will have to be entered specially. There are two ways to tell the
reader that a meta-character is actually part of the symbol's name:
\
), for
example:
xy\(z\) ;the symbol whose name is xy(z)
|
characters).
All characters after the starting vertical line are copied as-is until
the closing vertical line is encountered. For example:
xy|(z)| ;the symbol xy(z)
Here are some example read syntaxes.
setq ;setq
|setq| ;setq
\s\e\t\q ;setq
1 ; the number 1 \1 ; the symbol1
|!$%zf78&| ;!$%zf78&
foo|(bar)| ;foo(bar)
foo\(bar\) ;foo(bar)
All symbols have two basic attributes: print name and property list. Most important is the print name of the symbol. This is a string naming the symbol, after it has been defined (when the symbol is first created) it may not be changed.
symbol-name symbol | Function |
This function returns the print name of the symbol symbol.
(symbol-name 'unwind-protect) => "unwind-protect" |
The symbol's property list (or plist) is similar to an alist (see Association Lists), though stored differently, and provides a method of storing arbitrary extra values in each symbol. See Property Lists.
Although not strictly an attribute of the symbol, symbols also provide
a means of associating values with names (i.e. variables). Within a
defined context, a symbol may have a binding, this binding
associates the symbol with a memory location within which a value may
be stored. When writing Lisp programs, the value of a symbol's current
binding is accessed by writing the print name of the symbol. Similarly
the binding may be modified by using the setq
special form.
See Variables.
An obarray is the structure used to ensure that no two symbols have the same name and to provide quick access to a symbol given its name. An obarray is a vector, each element of the vector is a chain of symbols whose names share the same hash-code (a bucket). These symbols are chained together through links which are invisible to Lisp programs: if you examine an obarray you will see that each bucket looks as though it has at most one symbol stored in it.
The normal way to reference a symbol is simply to type its name in the program, when the Lisp reader encounters a name of a symbol it looks in the default obarray for a symbol of that name. If the named symbol doesn't exist it is created and hashed into the obarray--this process is known as interning the symbol, for more details see Interning.
obarray | Variable |
This variable contains the obarray that the read function uses when
interning symbols.
|
make-obarray size | Function |
This function creates a new obarray with size hash buckets (this
should probably be a prime number for the fewest hash collisions).
This is the only way of creating an obarray. |
find-symbol symbol-name #!optional obarray | Function |
This function scans the specified obarray (obarray or the value of
the variable obarray if obarray is undefined) for a symbol
whose name is the string symbol-name. The value returned is the
symbol if it can be found or false otherwise.
(find-symbol "setq") => setq |
apropos regexp #!optional predicate obarray | Function |
Returns a list of symbols from the obarray obarray (or the
default) whose print name matches the regular expression regexp
(see Regular Expressions). If predicate is true, each symbol
which matches regexp is applied to the function predicate,
if the value is true it is considered a match.
The predicate argument is useful for restricting matches to a certain type of symbol, for example only commands. (apropos "^yank" 'commandp) => (yank-rectangle yank yank-to-mouse) |
It is possible to allocate symbols dynamically, this is normally only necessary when the symbol is to be interned in a non-default obarray or the symbol is a temporary object which should not be interned (for example: labels in a compiler).
make-symbol print-name | Function |
This function creates and returns a new, uninterned, symbol whose print
name is the string print-name. Its value cell is void (undefined)
and it will have an empty property list.
(make-symbol "foo") => foo |
gensym | Function |
This function returns a new, uninterned, symbol that has a unique print
name.
(gensym) => G0001 (gensym) => G0002 |
Interning a symbol means to store it in an obarray so that it can be found in the future: all variables and named-functions are found through interned symbols.
When a symbol is interned a hash function is applied to its print name to determine which bucket in the obarray it should be stored in. Then it is simply pushed onto the front of that bucket's chain of symbols.
Normally all interning is done automatically by the Lisp reader. When
it encounters the name of a symbol which it can't find in the default
obarray (the value of the variable obarray
) it creates a new
symbol of that name and interns it. This means that no two symbols can
have the same print name, and that the read syntax of a particular
symbol always produces the same object (unless the value of
obarray
is altered).
(eq 'some-symbol 'some-symbol) => t
intern symbol-name #!optional obarray | Function |
This function uses find-symbol to search the obarray (or the
standard obarray) for a symbol called symbol-name. If a symbol of
that name is found it is returned, otherwise a new symbol of that name is
created, interned into the obarray, and returned.
(intern "setq") => setq (intern "my-symbol" my-obarray) => my-symbol |
intern-symbol symbol #!optional obarray | Function |
Interns the symbol symbol into the obarray obarray (or the
standard one) then returns the symbol. If symbol is currently
interned in an obarray an error is signalled.
(intern-symbol (make-symbol "foo")) => foo (intern-symbol 'foo) error--> Error: Symbol is already interned, foo |
unintern symbol #!optional obarray | Function |
This function removes the symbol symbol from the obarray obarray
then returns the symbol.
Beware! this function should be used with extreme caution--once you unintern a symbol there may be no way to recover it. (unintern 'setq) ;This is extremely stupid => setq |
Each symbol has a property list (or plist), this is a structure which associates an arbitrary Lisp object with a key (usually a symbol). The keys in a plist may not have any duplications (so that each property is only defined once).
The concept of a property list is very similar to an association list (see Association Lists) but there are two main differences:
((one . 1) (two . 2) (three . 3))
a property list would be,
(one 1 two 2 three 3)
get symbol property | Function |
This function searches the property list of the symbol symbol for
a property equal to property. If such a property is found
it is returned, otherwise false is returned.
(get 'if 'lisp-indent) => 2 (get 'set 'lisp-indent) => () |
put symbol property new-value | Function |
put sets the value of the property property to
new-value in the property list of the symbol symbol. If
there is an existing value for this property (using equal to
compare keys) it is overwritten. The value returned is new-value.
(put 'foo 'prop 200) => 200 |
symbol-plist symbol | Function |
Returns the property list of the symbol symbol.
(symbol-plist 'if) => (lisp-indent 2) |
setplist symbol plist | Function |
This function sets the property list of the symbol symbol to
plist.
(setplist 'foo '(zombie yes)) => (zombie yes) |
Keywords are a special class of symbols. They evaluate to themselves,
and have the read syntax #:symbol
, where symbol is
anything satisfying the usual symbol syntax. These objects are normally
used to mark keyword parameters in function applications (see Lambda Expressions).
make-keyword symbol | Function |
Return the keyword symbol that could be used to mark an argument value
for the keyword parameter symbol.
(make-keyword 'x) => #:x |
keywordp arg | Function |
Returns true if arg is a keyword symbol. |
So far only the primitive data types have been discussed, and how the Lisp reader converts textual descriptions of these types into Lisp objects. Obviously there has to be a way of actually computing something--it would be difficult to write a useful program otherwise.
What sets Lisp apart from other languages is that in Lisp there is no difference between programs and data: a Lisp program is just a sequence of Lisp objects which will be evaluated as a program when required.
The subsystem which does this evaluation is called the Lisp
evaluator and each expression to be evaluated is called a form.
The evaluator (the function eval
) examines the structure of the
form that is applied to it and computes the value of that form within
the current Lisp environment.
A form can be any type of data object; the only types which the evaluator treats specially are symbols (which describe variables) and lists (subroutine applications), anything else is returned as-is (and is called a self-evaluating form).
eval form | Function |
This function computes and returns the value of form within the current module and dynamic environment, and a null lexical environment. |
However, eval
is rarely explicitly invoked, except in the
read-eval-print loop. Lisp provides many other methods of evaluation
that are usually much more suitable within a program.
max-lisp-depth | Variable |
This variable limits the number of nested calls to eval . If more
than this many nested calls to eval exist, an error is
signalled. The intention is to detect infinite recursion before hitting
the stack size limit (causing a segmentation fault).
|
When the evaluator is applied to a symbol the computed value of the form is the value associated with the symbol in the current environment. Basically this means that to get the value of a variable you simply write its name. For example,
rep-version => "1.0"
this extract from a Lisp session shows the read syntax of a form to
get the value of the variable rep-version
and the result when
this form is evaluated.
Since forms are evaluated within the current environment the value of a variable is its most-recent extant binding (with slight differences for lexical and special variables). See Variables.
If an evaluated symbol has no current binding, an error is signalled.
Forms which are lists are used to invoke a subroutine. The first element of the list defines the subroutine to be called; all further elements are arguments to be applied to that subroutine invocation.
There are several different types of subroutines available: functions, macros, special forms and autoloads. When the evaluator finds a form which is a list it tries to classify the form into one of these four types.
First of all it evaluates the first element of the list; the computed value of this element decides how the rest of the elements in the list are treated. For example, if the first element is a symbol whose value is a function, then that function is called with the other values in the list.
When the first element of a list form evaluates to a function object (either a primitive subroutine or a closure), all other elements in the list are evaluated sequentially from left-to-right, then these values are applied to the function definition. The result returned by the function is then taken as the value of the whole list form.
For example, consider the form (/ 100 (1+ 4))
. This is a
function call to the function stored in the variable /
. First
the /
form is evaluated, it is a variable containing a data
value representing the primitive subroutine for integer division. Then
the 100
form is evaluated: it is a number, so self-evaluates to
the value 100
. Next the form (1+ 4)
is evaluated. This is
also a function call and computes to a value of 5
which becomes
the second argument to the /
function. Now the /
function
is applied to its evaluated arguments of 100
and 5
, and
returns the value 20
. This then becomes the value of the form
(/ 100 (1+ 4))
.
(/ 100 (1+ 4)) == (/ 100 5) => 20
Or another example,
(+ (- 10 (1- 7)) (* (1+ 2) 4) == (+ (- 10 6) (* (1+ 2) 4) == (+ 4 (* (1+ 2) 4) == (+ 4 (* 3 4)) == (+ 4 12) => 16
The system is also capable of eliminating tail calls where possible, allowing tail-recursive function definitions to run with bounded space requirements.
A tail-call is a function call that occurs immediately before exiting the containing function. Since the containing function need not receive the result of the function call, it is possible to, in effect, exit from the containing function before invoking the called function.
Note however, that this is only possible where none of the dynamic
features of the language (i.e. bindings to special variables,
unwind-protect
, condition-case
, catch
, etc...)
are currently active in the containing function.
Consider, for example, the following function:
(defun print-list (l) (unless (null l) (format standard-output "%s\n" (car l)) (print-list (cdr l))))
the call to print-list
occurs in the tail-position of the
function. This means that the call may be made after removing the
previous call to print-list
from the interpreter's stack of
active functions.
[ XXX currently the interpreter is incapable of eliminating tail calls to subrs, i.e. Lisp functions implemented in C ]
Macros are source code expansions, the general idea is that a macro is a function which using the unevaluated arguments applied to it, computes another form (the expansion of the macro and its arguments) which is then evaluated to provide the value of the form.
Macros are generally used to implement control-flow operations, where not all arguments may be evaluated, or evaluated in an unusual order. For more details see Macros.
Special forms are built-in subroutines which the evaluator knows must be handled specially. The main difference between a special form and a function is that the arguments applied to a special form are not automatically evaluated--if necessary the special form will evaluate arguments itself. This will be noted in the documentation of the special form.
Special forms are generally used to provide control structures, for example, the primitive conditional constructs are special forms (if all of their arguments, including the forms to be conditionally evaluated, were evaluated automatically this would defeat the object of being conditional!).
The special forms supported by librep
are: case
,
catch
, cond
, condition-case
, defvar
,
progn
, quote
, setq
, unwind-protect
.
special-form-p arg | Function |
Returns true if arg is a special form.
(special-form-p quote) => t |
Not all modules of librep
are needed at once, autoload forms
provide a means of marking that a function (or macro) is contained by a
specific Lisp library. The first time that the function is accessed the
autoload form will be evaluated; this loads the file containing the
function, then re-evaluates the original form. By then the autoload
form will have been overwritten in the symbol's function slot by the
true function (when it was loaded) so the form will execute properly.
For more details see Autoloading.
The computed value of any form which is not a symbol or a list will simply be the form itself and the form is said to be a self-evaluating form.
Usually the only forms to be evaluated in this way will be numbers, strings and vectors (since they are the only other data types which have read syntaxes) but the effect is the same for other types of data.
This means that forms you know are self-evaluating do not have to be quoted to be used as constants (like lists and symbols do).
"foo" => "foo"
As the above sections explain some types of Lisp object have special meaning to the Lisp evaluator (namely the symbol and list types) this means that if you want to refer to a symbol or a list in a program you can't because the evaluator will treat the form as either a variable reference or a function call respectively.
To get around this Lisp uses an idea called quoting. The special
form quote
simply returns its argument without evaluating it.
For example,
(quote my-symbol) => my-symbol
the quote
form prevents the my-symbol
being treated as a
variable--it is effectively `hidden' from the evaluator.
Writing quote
all the time would be a bit time-consuming so
there is a shortcut: the Lisp reader treats any form x preceded
by a single quote character ('
) as the form (quote
x)
. So the example above would normally be written as,
'my-symbol => my-symbol
The general way to prevent evaluation of a form is to simply precede it by a single quote-mark.
quote form | Special Form |
This special form returns its single argument without evaluating it. This is used to quote constant objects to prevent them from being evaluated. |
For another form of quoting, see Backquoting.
In Lisp, symbols are used to represent variables. Each symbol contains a value slot that is used to contain the value of the symbol when it used as a variable.
The normal way to obtain the current value of a variable is simply to
evaluate the symbol of the same name (i.e. write the name of the
variable in your program). The symbol-value
function can be used
to evaluate variables whose names not known statically.
symbol-value variable | Function |
This function returns the value of the symbol variable in the current environment. |
A local variable is a variable which has a temporary value. For example, when a function is called the variables which are the names of its arguments are temporarily bound to the values of the arguments passed to the function. When the function call exits its arguments are unbound and the previous definitions of the variables come back into view.
A binding is a particular instance of a local variable. Even if a variable has more than one binding currently in place, only the most recent is available--there is no way the previous binding can be accessed until the previous binding is removed.
One way of visualising variable binding is to think of each variable as a stack. When the variable is bound to, a new value is pushed onto the stack, when it is unbound the top of the stack is popped. Similarly when the stack is empty the value of the variable is void (see Void Variables). Assigning a value to the variable (see Setting Variables) overwrites the top value on the stack with a new value. When the value of the variable is required it is simply read from the top of the stack.
Apart from function applications there are two special forms which
perform variable binding (i.e. creating local variables), let
and let*
.
let bindings body-forms... | Macro |
let creates new variable bindings as specified by the
bindings argument, then evaluates the body-forms in order.
The bindings are then removed, returning all variables to their state
before the let statement was entered. The value of the statement
is the value of the implicit progn .
The bindings argument is a list of the bindings to perform. Each
binding is either a symbol, in which case that variable is bound to
(setq foo 42) => 42 (let ((foo (+ 1 2)) bar) ;; Body forms (setq foo (1+ foo)) ;This sets the new binding (cons foo bar)) => (4 . ()) foo => 42 ;The original values is back No bindings are made until all new values have been computed. For example: (setq foo 42) => 42 (let ((foo 100) (bar foo)) (cons foo bar)) => (100 . 42) Although |
let* bindings body-forms... | Macro |
This special form is exactly the same as let except for one
important difference: the new bindings are installed as they are
computed.
You can see the difference by comparing the following example with the
last example in the (setq foo 42)
=> 42
(let* ;Using
By the time the new value of |
letrec bindings body-forms... | Macro |
letrec is similar to let and let* , with the
differerence being that the values of bindings are evaluated with all
other bindings in scope. This means that recursive functions may be
defined with letrec . For example, a local factorial function
(from SICP):
(letrec ((fact (lambda (n) (if (= n 1) 1 (* n (fact (1- n))))))) (fact 10)) Note also that letrec allows groups of mutually recursive functions to be defined, as in the following example (also from SICP): (defun f (x) (letrec ((evenp (lambda (n) (if (= n 0) t (oddp (1- n))))) (oddp (lambda (n) (if (= n 0) nil (evenp (1- n)))))) ... |
Setting a variable means to overwrite its current value (that is, the value of its most recent active binding) with a new one. In the variable-as-stack analogy, this is analogous to overwriting the top of the stack. The old value is irretrievably lost (unlike when a new value is bound to a variable, see Local Variables).
The setq
special form is the usual method of altering the value
of a variable.
setq variable form ... | Special Form |
Each variable is set to the result of evaluating its
corresponding form. The last value assigned becomes the value of
the setq form.
(setq x 20 y (+ 2 3)) => 5 In the above example the variable |
set variable new-value | Function |
The value of the variable variable (a symbol) is set to
new-value and the new-value is returned.
This function is used when the variable is unknown until run-time, and therefore has to be computed from a form. (set 'foo 20)
==
(setq foo 20) ;
Note: currently the |
In the librep
dialect of Lisp by default variables have
lexical scope. This means that bindings are associated with
textual regions of programs, and may be accessed by any forms within
this associated textual region. Moreover, the bindings are persistent,
even when the flow of control is currently outside the associated
region.
Consider the following example:
(let ((counter 0)) (defun count () (setq counter (1+ counter)) counter))
the value of the counter
variable persists, and is incremented
each time the count
function is called. The counter
variable is accessible from nowhere but the forms written inside the
let
statement declaring it.
(count) => 1 (count) => 2
An alternative method of scoping variables is also available. Any
variables declared using the defvar
special form are said to be
special variables, they have indefinite scope and
dynamic extent, often simplified to dynamic scope. What
this means is that references to these variables may occur anywhere in
a program (i.e. bindings established in one function are visible within
functions called from the original function) and that references may
occur at any point in time between the binding being created and it
being unbound.
Dynamic scoping is easy to abuse, making programs hard to understand and debug. A quick example of the use of dynamic scope,
(defvar *foo-var* nil) (defun foo (x) (let ;; a dynamically-scoped binding ((*foo-var* (* x 20))) (bar x) ... (defun bar (y) ;; Since this function is called from ;; the functionfoo
it can refer ;; to*foo-var*
(setq y (+ y *foo-var*)) ...
As shown in the previous example, a common convention is to mark special variables by enclosing their names within asterisks.
A variable which has no value is said to be void, attempting to reference the value of such a symbol will result in an error. It is possible for the most recent binding of a variable to be void even though the inactive bindings may have values.
boundp variable | Function |
Returns true if the symbol variable has a value. |
makunbound variable | Function |
This function makes the current binding of the symbol variable be
void, then returns variable.
(setq foo 42) => 42 foo => 42 (boundp 'foo) => t (makunbound 'foo) => foo (boundp 'foo) => () foo error--> Value as variable is void: foo |
The special forms defvar
and defconst
allow you to define
the global variables that will be used by a program.
defvar variable form [doc-string] | Special Form |
This special form defines a special (i.e. dynamically scoped) variable,
the symbol variable. If the value of variable is void the
form is evaluated and its value is stored as the value of
variable (note that only the default value is modified, never a
buffer-local value).
If the doc-string argument is defined it is a string documenting
variable. This string is then stored as the symbol's
(defvar *my-variable* '(x y)
"This variable is an example showing the usage of the
|
defconst constant form [doc-string] | Macro |
defconst defines a global constant, the symbol constant.
Its value is set to the result of evaluating form. Note that
unlike defvar the value of the symbol is always set, even
if it already has a value.
The doc-string argument, if defined, is the documentation string for the constant. (defconst the-answer 42 "An example constant.") => the-answer |
Another way of defining global variables is to use the define
macro (see Definitions). The following example defines a global
variable foo
with value 42
. This is similar to both
defvar
and defconst
except that the defined variable
binding is both lexically scoped and mutable.
(define foo 42)
Special variables have a number of drawbacks, especially when used in
conjunction with the module system (see Modules and Special Variables). As a consequence of these drawbacks, rep
provides a
second method of implementing dynamically scoped variables, known as
fluid variables, or just fluids.
A fluid is a first class Lisp object that may be passed around as any other Lisp object. It's sole function is to provide a location from which dynamic bindings may be created. Fluids are anonymous objects, they are usually named by being stored in lexically scoped variables.
make-fluid #!optional value | Function |
Create and return a new fluid, it will have an initial binding of value (or false if value is undefined). |
fluid fluid | Function |
Return the value of the most recently created binding of the fluid variable object fluid. |
fluid-set fluid value | Function |
Set the value of the most recently created binding of the fluid variable object fluid to value. |
with-fluids fluids values thunk | Function |
Call the zero parameter function thunk (and return the value that
it returns) with new bindings created for each of the fluid variables
specified in the list fluids.
For each member of fluids the corresponding member of the values list provides the initial value of the new binding. If the lists fluids and values are not of the same length, an error is signalled. |
let-fluids bindings body ... | Macro |
A convenient wrapper around with-fluids , similar to the
let syntax.
The list bindings associates the names of lexical variables containing fluid objects, with the values to bind to those fluid objects. Once the bindings have been installed, the body ... forms are evaluated, and the bindings removed. The value of the last of the body ... forms is returned. |
Here is an example code fragment using fluid variables and
let-fluids
:
(define a (make-fluid)) (define b (make-fluid)) (let-fluids ((a 1) (b 2)) (+ (fluid a) (fluid b))) => 3
A function is a Lisp object which, when applied to a sequence of argument values, produces another value--the function's result. It may also induce side-effects (e.g. changing the environment of the calling function). All Lisp functions return results -- there is nothing like a procedure in Pascal.
Note that special forms (see Special Forms) and macros (see Macros) are not functions since they do not guarantee to evaluate all of their arguments.
Functions are the main building-block in Lisp programs, each program is usually a system of interrelated functions.
There are two types of function: primitive functions are functions written in the C language, these are sometimes called built-in functions, the object containing the C code itself is called a subr. All other functions are defined in Lisp.
functionp object | Function |
Returns true if object is a function (i.e. it can be used
as the function argument of funcall .
(functionp set) => t (functionp setq) => () (functionp (lambda (x) (+ x 2))) => t |
subrp arg | Function |
Returns true is arg is a primitive subroutine object. |
subr-name subr | Function |
Returns a string naming the primitive subroutine subr. |
Lambda expressions are used to create functions from other Lisp
objects. A lambda expression is a list whose first element is the
symbol lambda
. All functions written in Lisp (as opposed to the
primitive functions in C) are defined using lambda expressions.
The general format of a lambda expression is:
(lambda lambda-list [doc] [interactive-declaration] body-forms... )
Where lambda-list is a list defining the formal parameters of the
function, doc is an optional documentation string,
interactive-declaration is only required by interactive commands
3 and body-forms is the sequence of forms making up
the function body, evaluated using an implicit progn
.
The lambda-list is a list, it defines how the values applied to
the function are bound to local variables which represent the
parameters of the function. At its simplest it is simply a list of
symbols, each symbol will have the corresponding argument value bound
to it. For example, the lambda list (x y)
defines two format
parameters, x
and y
. When called with two arguments the
first will be bound to the variable x
, the second to y
.
When used in a full lambda expression this looks like:
(lambda (x y) (+ x y))
this evaluates to an anonymous function with two parameters, x
and y
, which when called evaluates to their sum.
Note that a lambda expression itself is not a function, it must be associated with a lexical environment, this conjunction is usually called a closure; it is the closure that may be called as a function.
However, to confuse matters, a lambda expression evaluates to the closure of itself and the current environment. Consider the following example:
(lambda (x) (1+ x)) => #<closure> (functionp (lambda (x) (1+ x))) => t (functionp '(lambda (x) (1+ x))) => ()
There are several lambda-list keywords which modify the meaning of symbols in the lambda-list. The syntax of the lambda list is:
([required-parameters...] [#!optional optional-parameters...] [#!key keyword-parameters...] [#!rest rest-parameter | . rest-parameter])
Each lambda list keyword is a symbol whose name begins #!
, they
are interpreted as follows:
#!optional
optional-parameters may either be of the form symbol
or of the form (symbol {No value for `default'})
. If no argument is
supplied for this parameter the default form is evaluated to give
the bound value4. If no default form
is given, then the variable is bound to a false value.
Note that optional parameters must be specified if a later parameter is also specified.
((lambda (#!optional a b) (list a b))) => (() ()) ((lambda (#!optional a b) (list a b)) 1) => (1 ()) ((lambda (#!optional a b) (list a b)) nil 1) => (() 1) ((lambda (#!optional (a 1)) (list a))) => (1) ((lambda (#!optional (a 1)) (list a)) 2) => (2)
#!key
#:symbol
.
As with optional parameters, default values may be supplied through the
use of the (symbol default)
syntax. If no default
value is given and no keyword argument of the specified kind is
available, the variable is bound to a false value.
For example, the lambda list (a #!key b c)
accepts one required
argument, and two optional keyword arguments. The variable a
would be bound to the first supplied argument; the variable b
would be bound to the argument preceded by the keyword #:b
, or
()
if no such argument exists. (After extracting required and
optional arguments, each remaining pair of values is checked for
associating a value with each keyword.)
((lambda (a #!key b c) (list a b c)) 1 2 3) => (1 () ()) ((lambda (a #!key b c) (list a b c)) 1 #:b 2 3) => (1 2 ()) ((lambda (a #!key b c) (list a b c)) 1 #:b 2 #:c 3) => (1 2 3) ((lambda (a #!key b c) (list a b c)) 1 #:c 3 #:b 2) => (1 2 3)
#!rest
#!rest
keyword allows a variable number of arguments to be
applied to a function, all the argument values which have not been
bound to argument variables (or used to mark keyword arguments) are
made into a list and bound to the variable following the #!rest
keyword. For example, in
(lambda (x #!rest y) ...)
the first argument, x
, is required. Any other arguments applied
to this function are made into a list and this list is bound to the
variable y
.
Variable argument functions may also be defined through the Scheme method of using an improper lambda-list. The previous example is exactly equivalent to:
(lambda (x . y) ...)
When a function represented by a lambda-list is called the first action is to bind the argument values to the formal parameters. The lambda-list and the list of argument values applied to the function are worked through in parallel. Any required arguments which are left undefined when the end of the argument values has been reached causes an error.
After the arguments have been processed the body-forms are evaluated by an implicit progn, the value of which becomes the value of the function call. Finally, all parameters are unbound and control passes back to the caller.
Globally accessible functions are usually defined by the defun
special form.
defun name lambda-list body-forms... | Macro |
defun initialises the function definition of the symbol
name to the lambda expression resulting from the concatenation of
the symbol lambda , lambda-list and the body-forms.
The body-forms may contain a documentation string for the function as its first form and an interactive calling specification as its first (if there is no doc-string) or second form if the function may be called interactively by the user (see Lambda Expressions). |
An example function definition taken from the librep
source code is:
(defun load-all (file) "Try to load files called FILE (or FILE.jl, etc) from all directories in the Lisp load path." (mapc (lambda (dir) (let ((full-name (expand-file-name file dir))) (when (or (file-exists-p full-name) (file-exists-p (concat full-name ".jl")) (file-exists-p (concat full-name ".jlc"))) (load full-name nil t)))) load-path))
When supplying functions as arguments to other functions it is often useful to give an actual function definition (i.e. an enclosed lambda expression) instead of the name of a function.
In Lisp, unlike most other programming languages, functions have no inherent name. As seen in the last section named-functions are created by storing a function object in a variable, if you want, a function can have many different names: simply store the function in many different variables!
So, when you want to pass a function as an argument there is the option
of just writing down its definition. This is especially useful with
functions like mapc
and delete-if
. For example, the
following form removes all elements from the list which are even
and greater than 20.
(setq list (delete-if (lambda (x) (and (zerop (% x 2)) (> x 20))) list))
The above lambda expression combines two predicates applied to its argument.
In certain cases it may be necessary to create a non-constant function,
for example by using backquoting (see Backquoting). In these cases
the make-closure
function may be used to create a function
object from a lambda expression.
make-closure arg | Function |
Return the closure of arg and the current lexical environment. |
closurep arg | Function |
Returns true if arg is a closure. |
closure-function closure | Function |
Returns the function object associated with the lexical closure closure. |
In Lisp, a function which returns a boolean `true' or boolean `false'
value is called a predicate. As is the convention in Lisp a value
of ()
means false, anything else means true. The symbols
nil
and t
are often used to represent constant false and
true values (see nil and t).
Another Lisp convention is that the names of predicate functions should
name the quality that the predicate is testing followed by either a
p
or -p
string. The p
variant is used when the
first string does not contain any hyphens.
For example, the predicate to test for the quality const-variable
(a variable which has a constant value, see Defining Variables) is
called const-variable-p
. On the other hand the predicate to test
for the quality cons (a Cons cell) is called consp
.
The defun
special form allows globally-accessible functions to
be defined. It is often desirable to declare functions local to the
current lexical environment. The let
and let*
special
form that were introduced earlier allow this since named functions are
simply functional values stored in variables.
For example,
(let ((temporary-function (lambda (x) (+ x 42)))) ... (temporary-function 20) ...
Most of the time function applications are made by the evaluator when it finds a functional value after evaluating the first element of a list form. However two functions are available for manually calling functions.
funcall function #!rest args | Function |
Applies the argument values args to the function function, then returns its result. |
apply function #!rest args | Function |
Similar to funcall except that the last of its arguments is
a list of arguments which are appended to the other members of
args to form the list of argument values to apply to the
function function.
(apply + 1 '(2 3)) => 6 (apply + (make-list 1000000 1)) => 1000000 |
A mapping function applies a function to each of a collection of
objects. librep
currently has two mapping functions,
mapcar
and mapc
.
mapcar function list | Function |
Each element of list is individually applied to the function
function. The values returned are made into a new list which is
returned.
The function must accept a single argument value. (mapcar 1+ '(1 2 3 4 5)) => (2 3 4 5 6) |
mapc function list | Function |
Similar to mapcar except that the values returned when each
element is applied to the function function are discarded. The
value returned is undefined.
This function is generally used where the side effects of calling the function are the important thing, not the results. It is often the most efficient way of traversing all items in a list, for example: (mapc (lambda (x) (print x standard-error)) list) |
The two following functions are also mapping functions of a sort. They
are variants of the delete
function (see Modifying Lists)
and use predicate functions to classify the elements of the list which
are to be deleted.
delete-if predicate list | Function |
This function is a variant of the delete function. Instead of
comparing each element of list with a specified object, each
element of list is applied to the predicate function
predicate. If it returns true then the
element is destructively removed from list.
(delete-if stringp '(1 "foo" 2 "bar" 3 "baz")) => (1 2 3) |
delete-if-not predicate list | Function |
This function does the inverse of delete-if . It applies
predicate to each element of list, if it returns false
then the element is destructively removed from the list.
(delete-if-not stringp '(1 "foo" 2 "bar" 3 "baz")) => ("foo" "bar" "baz") |
The filter
function is similar to delete-if-not
, except
that the original list isn't modified, a new list is created.
filter predicate list | Function |
Return a new list, consisting of the elements in list which the
function predicate returns true when applied to. This
function is equivalent to:
(mapcar nconc (mapcar (lambda (x) (and (predicate x) (list x))) list)) |
Macros are used to extend the Lisp language. They consist of a function which instead of returning a computed value, transform their unevaluated arguments into a new form that, when evaluated, produces the actual value of the original form.
For example, the when
macro (see Conditional Structures)
implements a new conditional operation by transforming its arguments
into a cond
statement. That is,
(when condition form ...) ==> (cond (condition form ...))
Since macros do not evaluate their arguments, instead just transforming them, they may be expanded at compile-time. The resulting form is then compiled as usual.
macrop arg | Function |
Returns true if arg is a macro object. |
Macros are defined in the same style as functions, the only difference is the name of the special form used to define them.
A macro object is a list whose car is the symbol macro
, its
cdr is the function which creates the expansion of the macro when
applied to the macro calls unevaluated arguments.
defmacro name lambda-list body-forms... | Macro |
Defines the macro stored in the function cell of the symbol name. lambda-list is the lambda-list specifying the arguments to the macro (see Lambda Expressions) and body-forms are the forms evaluated when the macro is expanded. The first of body-forms may be a documentation string describing the macro's use. |
Here is a simple macro definition, it is the definition of the
when
macro shown in the previous section.
(defmacro when (condition #!rest body) "Evaluates condition, if it's true evaluates the body forms." (list 'cond (list* condition body)))
When a form of the type (when c b ...)
is
evaluated the macro definition of when
expands to the form
(cond (c (progn b ...)))
which is then evaluated
to perform the when
-construct.
When you define a macro ensure that the forms which produce the expansion have no side effects; otherwise undefined effects will occur when programs using the macro are compiled.
As seen in the previous sections, macros are a very powerful mechanism of defining new control structures. However due to the need to create the expansion, i.e. the form that will be actually evaluated, they can often be complex to write and understand.
We have already seen that constants may be produced through the use of
the quote-mark (see Quoting), here another form of quoting is
described, where only some of the quoted object is actually constant.
This is known as backquoting, since it is introduced by the
backquote character `
, a shortcut for the backquote
macro.
backquote arg | Macro |
Constructs a new version of arg (a list). All parts of list
are preserved except for expressions introduced by comma (, )
characters, which are evaluated and spliced into the list. For example:
`(1 2 ,(+ 1 2)) => (1 2 3) Also, the `(1 2 ,@(list 3)) => (1 2 3) |
Backquoting allows macros expansions to be created from static
templates. For example the when
macro shown in the previous
sections can be rewritten as:
(defmacro when (condition #!rest body) `(cond (,condition ,@body)))
which is easier to read, since it is a lot closer to the actual expansion.
When a macro call is detected (see List Forms) the function which is the cdr of the macro's definition (see Defining Macros) is applied to the macro call's arguments. Unlike in a function call, the arguments are not evaluated, the actual forms are the arguments to the macro's expansion function. This is to allow these forms to be rearranged by the macro's expansion function, creating the form that will finally be evaluated.
There is a function which performs macro expansion, its main use is to let the Lisp compiler expand macro calls at compile time.
macroexpand form #!optional environment | Function |
If form is a macro call macroexpand will expand that call
by calling the macro's expansion function (the cdr of the macro definition).
If this expansion is another macro call the process is repeated until
an expansion is obtained which is not a macro call, this form is
then returned.
The optional environment argument is an alist of macro definitions to use as well as the existing macros; this is mainly used for compilation purposes. (defmacro when (condition #!rest body) "Evaluates condition, if it's true evaluates the body forms." (list 'if condition (cons 'progn body))) => when (macroexpand '(when x (setq foo bar))) => (if x (progn (setq foo bar))) While a macro is being expanded, the special variable
|
Although it may seem odd that macros return a form to produce a result and not simply the result itself, this is actually their most important feature. It allows the expansion and the evaluation of the expansion to occur at different times.
The Lisp compiler makes use of this; when it comes across a macro call
in a form it is compiling it uses the macroexpand
function to
produce the expansion of that form. This expansion is then compiled
straight into the object code. Obviously this is good for performance
(why evaluate the expansion every time it is needed when once will
do?).
Some rules do need to be observed to make this work properly:
require
function, the compiler will evaluate
any require
forms it sees loading any macro definitions used.
Note however, that the librep
compiler does allow macros to be
used before they are defined (two passes are made through the source
file).
Previous sections of this document have described several special forms
and macros for defining top-level functions and variables.
librep
also provides a higher-level method of creating these
definitions, the define
statement. define
originates in
the Scheme dialect of Lisp, it allows block-structured programs to be
defined intuitively.
The most basic use of define
is very similar to defun
,
e.g. the two following forms have exactly the same effect:
(defun foo (x) (1+ x)) (define (foo x) (1+ x))
But note the changed position of the parentheses. This is because
define
may also be used to define (lexical) variables. Hence the
following is also equivalent:
(define foo (lambda (x) (1+ x)))
However this is the most uninteresting aspect of define
. More
interesting is that it allows internal definitions.
Within a define
form, any inner calls to define
(that
occur in a contiguous block at the start of the body of a let
,
let*
, letrec
, lambda
, or define
form) are
also used to create definitions, but definitions that are local to the
containing scope. For example:
(define (foo x) (define (bar x) (* x 42)) (1+ (bar x)))
This defines a top-level function called foo
; but this also
contains an inner function named bar
, that is only accessible
within foo
. 5
define name form | Macro |
define (name . args) body-forms... | Macro |
Define a global lexical variable called name, whose value will be
set to form.
If the first argument to the macro is a list, then a function is
defined whose name is name and whose formal parameters are
specified by args. The body of the function is defined by the
body-forms. The body forms have any macros expanded, and are
scanned for internal definitions (at the start of the body of
|
with-internal-definitions body-forms | Macro |
Recursively expand macros in body-forms, while scanning out any
internal definitions into letrec statements.
|
When creating large programs from many separate components, it is
important to be able to encapsulate these components, such that the
interfaces they present to other components are well defined, and the
implementations of these interfaces may be modified without affecting
any other components. To this end rep
provides a module
system for managing the scope of global definitions. This module
system was inspired by the Scheme48, Xerox Scheme and Standard ML
module systems.
Modules are known as structures and may be anonymous or named. Each structure specifies and implements an interface, essentially a list of names listing the definitions within the module that may be referenced by other modules. Each structure is a separate global namespace, with a number of variable bindings. Each closure contains a reference to the structure it was instantiated in, providing the source for referencing any unbound variables.
As well as specifying its name and interface, each module also lists the other modules whose bindings it may reference. Structures may either open or access other structures; when opening a structure all its exported bindings are immediately referenceable from the importing module. Exported bindings from accessed structures are referenced using the `structure-ref' form.
Each module implements an interface--the set of bindings (i.e. functions, macros or variables) that it exports to other modules. Interfaces may either be defined and then referenced by name, written literally, or combined from a number of sources.
The syntax of interface definitions is as follows:
interface -> (export id ...) | name | (compound-interface interface ...) | (structure-interface module-name)
where each id is the name of a binding to export, and each
name is the name of an interface previously defined using
define-interface
.
define-interface name interface | Macro |
Associate the symbol name with the module interface interface (using one of the forms listed above. |
Here is an example defining an interface called foo
:
(define-interface foo (compound-interface bar (export baz quux)))
It includes the interface called bar
and adds two extra exported
symbols: baz
and quux
.
Two special forms are used to define modules, one for anonymous modules, one for named modules. When storing modules in files, each file often contains a single instance of one of these forms.
structure interface config body... | Macro |
define-structure name interface config body... | Macro |
These special forms each create a new module with interface
interface (using the syntax described in the previous section),
and configuration config.
After configuring the module as specified, the sequence of forms body... is evaluated; it should include the definitions required to fulfil the interface that the module has promised to exhibit. The config form is either a list of configuration clauses, or a single configuration clause. Each such clause must be of the following syntax: clause -> (open name ...) | (access name ...) Each name specifies the name of a module, in the case of
Alternatively, if an (structure-ref foo bar) Since this form is used so often, the reader allows the abbreviation
|
Note that to access the standard features of the rep
language
described in this manual, modules need to import the rep
module.
Alternatively, they may import the scheme
module to load a
minimal R4RS Scheme environment.
Here is an example module definition, defining a module named
test
that exports two functions foo
and bar
.
(define-structure test (export foo bar) (open rep) (define (foo x) (* x 42)) (define (bar x y) (+ (foo x) (1+ y))))
It is also possible to export multiple views of a single underlying set
of bindings, by using the define-structures
form to create a
number of modules.
define-structures ((name interface) ...) config body... | Macro |
Create a module for each (name interface) pair. The
module is called name and exports the interface defined by
interface.
The config and body... forms are as in
Here is a trivial example: (define-structures ((foo (export foo both)) (bar (export bar both))) (open rep) (define both 1) (define foo 2) (define bar 3)) the underlying environment has three bindings. Each created module exports two of these. |
As described above, the common way of loading modules is to use the
open
and access
clauses of the configuration language.
If the modules named by these clauses are not currently loaded into the
interpreter, then the system will attempt to load them from the filing
system, using the standard load-path
variable to define the
directories to search.
To allow modules names to be hierarchical, any dot characters in a
module's name are replaced by the operating system's directory
separator string (i.e. on unix, all .
characters are simply
replaced by /
characters).
When searching for files to load, the standard filename suffixes are
used to differentiate Lisp files from other types of files (see Load Function). This file should contain a define-structure
form (as
described in the previous section) as the last top-level form in the
file.
For backwards compatibility, the require
function can also be
used to import modules. If a module of the same name as the requested
feature has already been loaded, then it is imported into the current
module. Otherwise if a file is loaded that contains a module definition
as its last top-level form, this module is imported into the current
module. See Features.
As described earlier, the defvar
special form may be used to
create variables that are scoped dynamically, known as special
variables, see Defining Variables. Due to their dynamic scope,
special variables do not fit well with the lexically scoped module
system described here.
As a result of this mismatch, special variables are stored in a separate namespace. This means that modules defining special variables must take the necessary steps to avoid the names of these variables clashing with those declared in other modules6.
In fact, it is often advisable to avoid using special variables as much as possible, especially when writing modules of Lisp code. An alternative method of creating dynamically scoped variables is to use fluid variable objects. These use first class Lisp objects to represent anonymous dynamically scoped variables. Since they are just Lisp objects, they may be stored in lexically scoped variables--this gives the benefits of both lexical (i.e. encapsulation) and dynamic scoping. See Fluid Variables.
Control structures are special forms or macros that control which forms get evaluated, when they get evaluated and the number of times to evaluate them. This includes conditional structures, loops, etc...
The simplest control structures are the sequencing structures; they are used to evaluate a list of forms in left to right order.
Each of the special forms in this section simply evaluates its arguments in left-to-right order. The only difference is the result returned.
The most widely used sequencing special form is progn
: it
evaluates all its argument forms and returns the computed value of the last
one. Many other control structures are said to perform an implicit progn,
this means that internally they call progn
with a list of forms.
progn
in Lisp is nearly analogous to a begin...end
block in Pascal; it is used in much the same places--to allow you to
evaluate a sequence of form where only one form was allowed (for
example the "true" clause of an if
structure).
progn forms... | Special Form |
All of the forms are evaluated sequentially (from left-to-right),
the result of the last evaluated form is the return value of the
special form. If no arguments are given to progn it returns
false.
(progn 'one (+ 1 1) "three") => "three" (progn) => () |
prog1 first forms... | Macro |
This special form evaluates its first form then performs an
implicit progn on the rest of its arguments. The result of this
structure is the computed value of the first form.
(prog1 'one (+ 1 1) "three") => one |
prog2 first second forms... | Macro |
This is similar to prog1 except that the evaluation of its
second form is returned.
The first form is evaluated, then its second, then it performs an implicit progn on the remaining arguments. (prog2 'one (+ 1 1) "three") => 2 |
Lisp provides a number of conditional constructs, the most complex of
which (cond
) takes a list of conditions, the first of which
evaluates to true has its
associated list of forms evaluated. Theoretically this is the only
conditional special form necessary--all others can be implemented as
macros.
if condition true-form else-forms... | Macro |
The if construct is the nearest thing in Lisp to the if-then-else
construct found in most programming languages.
First the condition form is evaluated, if it returns true the true-form is evaluated and its result returned. Otherwise the result of an implicit progn on the else-forms is returned. If there are no else-forms false is returned. Note that one of the true-form or the else-forms is completely ignored--it is not evaluated. (if (special-form-p if) "`if' is a special form" "`if' is not a special form") => "`if' is not a special form" |
when condition true-forms... | Macro |
condition is evaluated, if it is true the result of an
implicit progn on the true-forms is returned, otherwise
false is returned.
(when t (message "Pointless") 'foo) => foo |
unless condition else-forms... | Macro |
This special form evaluates condition, if its computed value is
true, () is returned. Otherwise the else-forms are
evaluated sequentially, the value of the last is returned.
|
cond clause... | Special Form |
The cond special form is used to choose between an arbitrary
number of conditions. Each clause is a list; the car of which is
a condition, the cdr is a list of forms to evaluate (in an
implicit progn if the condition evaluates to true.
This means that each clause looks something like:
(condition body-forms...) and a whole (cond (condition-1 body-forms-1...) (condition-2 body-forms-2...) ...) The condition in each clause is evaluated in sequence
(condition-1, then condition-2, ...), the first one
which evaluates to a true value has an implicit If the true condition has no body-forms the value returned
is the value of the condition. If none of the clauses has a
true condition the value of the Often you want a default clause which has its body-forms
evaluated when none of the other clauses are true. The way to do this
is to add a clause with a condition of (cond ((stringp buffer-list)) ;Clause with no body-forms ((consp buffer-list) (setq x buffer-list) ;Two body-forms t) (t ;Default clause (error "`buffer-list' is corrupted!"))) => t |
case key clauses... | Macro |
This special form is similar to cond , but switches on the result
of evaluating a single form key, checking for equality with a
number of other values, defined by the clauses. If any of these
other values is the same as the result of evaluating key, then a
sequence of forms associated with the value is evaluated.
Each element of the clauses list has the format: ((value-1 value-2 ... value-n) forms...) Each of the values in the car of the clause is tested for equality with
key, using the Instead of supplying a list of possible values, it is also possible to
just specify the symbol If any of the values in the clauses appear multiply, then the behaviour of the construct is undefined. Here is an example use of (case foo ((bar baz) (print "It was either bar or baz")) ((quux) (print "It was quux")) (t (print "I've no idea what it was..."))) |
There are also a number of special forms which combine conditions together by the normal logical rules.
or forms... | Macro |
The first of the forms is evaluated, if it is true its
value is the value of the or form and no more of forms
are evaluated. Otherwise this step is repeated for the next member of
forms.
If all of the forms have been evaluated and none have a
true value the (or nil 1 nil (beep)) ;
|
and forms... | Macro |
The first of the forms is evaluated. If it is false no more
of the forms are evaluated and false is the value of
the and statement. Otherwise the next member of forms is
evaluated and its value tested. If none of the forms are
false the computed value of the last member of forms is
returned from the and form.
(and 1 2 nil (beep)) ;
|
not object | Function |
This function inverts the truth value of its argument. If object
is true, false is returned, otherwise true is
returned.
(not nil) => t (not t) => () (not (not 42)) => t |
The librep
Lisp dialect only has one method of creating looping
control structures--recursion. Any looping construct found in an
imperative language can be represented as a recursive function. For
example the common while
statement:
(while condition body...) == (letrec ((loop (lambda () (when condition body (loop))))) (loop))
Each successive iteration of the loop is simply another call to the
function. Also note that the recursive call to the (loop)
function occurs in the tail-position of the function. When combined
with the system's ability to eliminate tail-calls (see Function Call Forms) the above example loop has bounded space requirements. This is
important when loops make a large number of iterations.
Although tail-recursion is the only primitive method of looping, the language offers a number of looping forms for convenience.
do vars (test expr...) body... | Macro |
do is an iteration construct; vars specifies a set of
variable bindings to be created, how they are initialized and how they
are updated on each iteration. test specifies the termination
condition of the loop, any expr... forms are evaluated
immediately prior to exiting the `do' construct. The body...
forms specify the side effecting body of the loop.
vars is a list of variable clauses, each of which has the
structure Each iteration begins by evaluating test, if the result is false, then the body... expressions are evaluated, and the variables bound to new locations initialized to the results of evaluating the associated step forms. If the result of evaluating test is true then the
expr... forms are evaluated, and the (do ((vec (make-vector 5)) (i 0 (1+ i))) ((= i 5) vec) (aset vec i i)) => [0 1 2 3 4] |
The "named-let" variant of the let
form also provides a
convenient looping construct.
let variable bindings body... | Macro |
This is the same as the (let bindings body...)
form described in Local Variables, but within the
body... forms, the symbol variable is bound to a
function whose parameters are the bound variables defined by
bindings and whose body is the sequence of forms
body...
This means that the body of the (let loop ((rest '(1 2 3)) (total 0)) (if (null rest) total (loop (cdr rest) (+ total (car rest))))) => 6 |
Finally, the imperative while
form shown at the start of the
section is also provided:
while condition body... | Macro |
The condition form is evaluated. If it is true an
implicit progn is performed on the body forms and the whole
procedure is repeated.
This continues until the condition form evaluates to false.
The value of every |
A non-local exit is a transfer of control from the current point
of evaluation to a different point (somewhat similar to the
much-maligned goto
statement in imperative languages).
Non-local exits can either be used explicitly (catch
and
throw
) or implicitly (errors).
The catch
and throw
structures are used to perform
explicit transfers of control. First a catch
form is used to
setup a tag; this acts like a label for a goto
statement.
To transfer control a throw
form is then used to transfer to the
named tag. The tag is destroyed and the catch
form exits with
the value provided by the throw
.
In a program this looks like,
(catch 'tag ;; Forms which may `throw' back to tag ... (throw 'tag value) ;; Control has now passed to the `catch', ;; no more forms in this progn will be evaluated. ...) => value
where tag is the tag to be used (this is normally a symbol) and
value is the result of the catch
form.
When a throw actually happens all catches in scope are searched for one
with a tag which is eq
to the tag in the throw. If more than one
exists the innermost is selected. Now that the catch has been located
the environment is `wound-back' to the catch's position (i.e. local
variables are unbound, cleanup forms executed, unused catches removed,
etc...) and all Lisp constructs between the current point of
control and the catch are immediately exited.
For example,
(let ((test 'outer)) (cons (catch 'foo (let ((test 'inner)) (throw 'foo test) (setq test 'unreachable))) ;Never reached test)) => (inner . outer)
when the throw executes the second binding of test
is unwound
and the first binding comes back into effect. For more details on
variable binding see Local Variables.
Note that catch tags are dynamically scoped, the thrower does
not have to be within the same lexical scope (this means that you can
throw
through functions).
catch tag body-forms... | Macro |
This special form defines a catch tag which will be accessible while the
body-forms are evaluated.
tag is evaluated and recorded as the tag for this catch. Next the
body-forms are evaluated as an implicit Before exiting, the tag installed by this form is removed. |
throw tag #!optional catch-value | Function |
This function transfers the point of control to the catch form with a
tag which is eq to tag. The value returned by this catch
form is either catch-value or false if catch-value is
undefined.
If there is no catch with a tag of tag an error is signalled and the interpreter returns to the top-level of evaluation. |
There are a number of pre-defined throw tags:
quit
librep
interpreter, returning the value of the
throw (if a number).
exit
user-interrupt
SIGINT
or C-c signal has been received. Control
passes back to the top-level event loop.
term-interrupt
SIGTERM
or SIGHUP
signal is received.
Tries to clean up any existing state, then terminates the interpreter.
Note that it is the event loop that catches these tags. If no event loop is active (i.e. just in read-eval-print on the console mode), any uncaught throws will result in termination.
librep
has no explicit return
statement, as found in most
other languages. Where a value has to returned from a function before
the function would normally exit, a catch
/throw
pair may
be used.
For example:
(defun foo (x y) (catch 'return (when (= x 2) (throw 'return nil)) ...
It is sometimes necessary ensure that a certain form is always
evaluated, even when a non-local exit would normally bypass that form.
The unwind-protect
special form is used in this case.
unwind-protect body-form cleanup-forms... | Macro |
The body-form is evaluated, if it exits normally the cleanup-forms
are evaluated sequentially then the value which the body-form
returned becomes the value of the unwind-protect form. If the
body-form exits abnormally though (i.e. a non-local exit happened)
the cleanup-forms are evaluated anyway and the non-local exit
continues.
|
One use of this is to ensure that an opened file is always closed, for example,
(catch 'foo (unwind-protect (let ((temporary-file (open-file (make-temp-name) 'write))) ;; Usetemporary-file
(write temporary-file "A test\n") ;; Now force a non-local exit (throw 'foo)) ;; This is the cleanup-form it will always ;; be evaluated, despite thethrow
. (close temporary-file))) => ()
Errors are a type of non-local exit; when a form can not be evaluated for some reason an error is normally signalled. If an error-handler has been installed for that type of error, control is passed to the handler for that error, and evaluation continues. If there is no suitable handler, control is passed back to the innermost input loop and a suitable error message is printed.
signal error-symbol data | Function |
Signals that an error has happened. error-symbol is a symbol
classifying the type of error, it should have a property
error-message (a string) which is the error message to be
printed.
data is a list of objects which are relevant to the error -- they will be made available to any error-handler or printed with the error message otherwise. (signal 'void-value '(some-symbol)) error--> Value as variable is void: some-symbol |
debug-on-error | Variable |
This variable is consulted by the function signal . If its value
is either t or a list containing the error-symbol to
signal as one of its elements, the Lisp debugger is entered.
When the debugger exits the error is signalled as normal.
|
backtrace-on-error | Variable |
Similar to debug-on-error , but if an error is matched, the
current backtrace is printed to the standard error stream, and control
continues.
|
When you expect an error to occur and need to be able to regain control
afterwards the condition-case
special form may be used.
condition-case symbol body-form error-handlers... | Macro |
condition-case evaluates the body-form with the
error-handlers in place. If an error occurs and one of the
handles matches the error, then it is evaluated with the value of
symbol set to the error information.
Each of the error-handlers is a list whose car is a symbol
defining the type of error which this handler catches. The cdr of the
list is a list of forms to be evaluated in a While the forms of the error handler are being evaluated the variable
symbol is bound to the value The special value, the symbol (condition-case data (signal 'file-error '("File not found" "/tmp/foo")) (file-error data) (error (setq x z))) ;Default handler => (file-error "File not found" "/tmp/foo") |
Whenever a function is called, there is a control path waiting to receive the result of the function, e.g. often the form following the function invocation. This waiting control path is called the continuation of the function, since control will continue down this path when the called function exits.
These continuations are usually not paid much thought, but in some
cases it may be useful to be able to directly manipulate the
continuation of a function. For this purpose rep provides the
call-with-current-continuation
function (often shortened to
call/cc
) that is standard in the Scheme dialect of Lisp.
call/cc function | Function |
function is a function with a single parameter; it will be
immediately invoked with this parameter bound to an object representing
the current continuation (i.e. the control path that would be taken
after function exits).
The continuation object passed to function is itself a function accepting a single argument, when called it transfers control to the continuation of function, as if function had returned the argument applied to the continuation object. |
call-with-current-continuation function | Function |
This is an alias for call/cc .
|
In its simplest form, call/cc
can mimic the catch
and
throw
procedures (see Catch and Throw), for example:
(defun foo (bar) (call/cc (lambda (esc) (when (null bar) ;; throws out of the call/cc (esc nil)) ;; do something with bar ...
this is roughly equivalent to:
(defun foo (bar) (catch 'tag (when (null bar) (throw 'tag nil)) ;; do something with bar ...
This is only half the story--the most powerful feature of
call/cc
is that since continuations have dynamic extent (that
is, no object is freed until no references to it exist) it is possible
to return control to scopes that have already exited.
For example, consider the following fragment of a lisp interaction:
(prog1 (call/cc (lambda (esc) (setq cont esc))) (message "foo!")) -| foo! => #<closure> cont => #<closure> (cont 10) -| foo! => 10
The continuation of the prog1
form is saved into the variable
cont
. When subsequently called with a single argument, it has
exactly the same effect as the first time that the second form in the
prog1
construct was evaluated.
call/cc
works by making a copy of the process' entire call
stack. For this reason, it is likely to be less efficient than using
the control structures described in the previous parts of this section.
Of course, it is much more powerful than the other constructs, so this
often outweighs the slight inefficiency.
Also note that currently no attempt is made to save or restore the
dynamic state of the Lisp system, apart from variable bindings (both
lexical and special). This means that any unwind-protect
,
condition-case
or catch
forms that are active when
invoking a continuation are all ignored.
Another restriction is that invoking a continuation may not cause control to pass across a dynamic root (see Threads).
librep
supports a simple model of multi-threaded programming.
Multiple threads of execution may be created, with control preemptively
being switched between them.
Unless otherwise noted, all definitions described in this section are
provided by the rep.threads
module.
Every thread created by rep is a member of a thread context, this context is defined by the current position in the lisp call stack. At any point in time, only threads which are members of the current context may be executing.
call-with-dynamic-root thunk | Function |
Call the function of zero-parameters thunk in a new thread
context. The new context will contain a single thread, that executing
thunk.
The call to |
The make-thread
function may be used to create threads that
execute within the current thread context (dynamic root). Each thread
is represented by a lisp object.
threadp arg | Function |
Return true if lisp object arg represents a thread of execution in the lisp environment. |
make-thread thunk #!optional name | Function |
Create and return a new thread of execution; it will initially invoke
the zero-parameter function thunk. If the call to thunk
returns the thread is automatically deleted.
If name is defined, it is a string naming the current thread. |
current-thread | Function |
Returns the currently executing thread. If no threads have been created yet in the current dynamic root (i.e. there is a single "implicit" thread) then false is returned. |
all-threads | Function |
Returns a newly-created list containing all threads in the current dynamic root. If no threads have been created yet, returns a null list. |
A thread may be deleted by either returning from the function specified
when it was created, or by explicit deletion. Also, the implicit thread
created by the call-with-dynamic-root
function may be deleted by
exiting from the function called in the new context.
thread-delete #!optional thread | Function |
Mark thread (or the current thread), as being deleted. It will not be switched to in the future. If the current thread is deleted, control will be passed to the next runnable thread. Deleting the last runnable thread results forces the containing dynamic root to be closed. |
thread-deleted-p thread | Function |
Returns true if thread has been deleted. |
thread-yield | Function |
This function may be used to pass control away from the current thread if other threads are waiting to run. There is usually no need to call this function since running threads will be preempted after a period of time. |
thread-suspend #!optional thread milliseconds | Function |
Mark thread (or the current thread) as being suspended. It will
not be selected until either it has had this status removed, or
milliseconds milliseconds time has passed.
Suspending the current thread will pass control to the next runnable thread in the same dynamic root. If there are no runnable threads, then the interpreter will sleep until the next thread becomes runnable. |
thread-join thread #!optional timeout default-value | Function |
Suspends the current thread until either thread has exited, or
timeout milliseconds have passed.
If thread exits normally, then the value of the last form it evaluated is returned; otherwise default-value is returned. |
thread-wake thread | Function |
Remove the suspended state from thread thread. It will then be scheduled for execution sometime subsequently, if its dynamic root is active. |
thread-suspended-p thread | Function |
Returns true if thread is currently suspended. |
Thread preemption may be forbidden at times, to allow atomic operations to take place. Each dynamic root has its own "forbid counter". Only when this counter is zero may the current thread be preempted.
thread-forbid | Function |
Increment the forbid count. |
thread-permit | Function |
Decrement the forbid count. |
without-interrupts #!rest forms | Macro |
Evaluate the list of forms forms with thread preemption temporarily disabled. |
Mutexes are lisp objects used to coordinate access to data shared
across multiple threads (where interleaved access would be bad). These
functions are exported by the rep.threads.mutex
module
(see Modules).
make-mutex | Function |
Create and return a mutex object. No thread will own the new mutex. |
mutexp arg | Function |
Return true if arg is a mutex object. |
obtain-mutex mutex | Function |
Obtain the mutex mutex for the current thread. Will suspend the current thread until the mutex is exclusively available. |
maybe-obtain-mutex mutex | Function |
Attempt to obtain mutex mutex for the current thread without blocking. Returns true if able to obtain the mutex, false otherwise. |
release-mutex mutex | Function |
Release the mutex object mutex (which must have previously been obtained by the current thread). Returns true if the mutex has no new owner. |
The threads used by librep
are software threads. This
means that they are currently implemented by manually switching in and
out thread context (i.e. the call stack) as required. There are a
number of disadvantages to this method:
The main advantage is the ease of implementation, especially when retrofitting threads into the previously single-threaded interpreter.
In Lisp, programs (also called modules, or libraries) are stored in files. Each file is a sequence of Lisp forms (known as top-level forms). Most of the top-level forms in a program will be definitions (i.e. function, macro or variable definitions) since generally each library is a system of related functions and variables.
Before the program can be used it has to be loaded into the editor's workspace; this involves reading and evaluating each top-level form in the file, i.e. instantiating all function definitions, or whatever.
load program #!optional no-error no-path no-suffix | Function |
This function loads the file containing the program called program;
first the file is located then each top-level form contained by the file
is read and evaluated in order.
Each directory named by the variable
If none of these gives a result the next directory is searched in the
same way, when all directories in Next the file is opened for reading and Lisp forms are read from it one at a time, each form is evaluated before the next form is read. When the end of the file is reached the file has been loaded and this function returns true. The optional arguments to this function are used to modify its behaviour,
If a version of the program whose name ends in If no Lisp file can be found matching program, then each
directory in the variable |
load-filename | Variable |
Whilst loading a Lisp library, this variable is bound to the name of the file being loaded. |
load-path | Variable |
A list of strings, each element is the name of a directory which is
prefixed to the name of a program when Lisp program files are being
searched for.
load-path => ("/usr/local/lib/rep/1.0/lisp/" "/usr/local/lib/rep/site-lisp/" "") The element |
dl-load-path | Variable |
A list of strings defining all directories to search for shared libraries. |
lisp-lib-directory | Variable |
The name of the directory in which the standard Lisp files are stored.
lisp-lib-dir => "/usr/local/lib/rep/1.0/lisp/" |
after-load-alist | Variable |
An association list of elements of the format (file
forms ...) . When the library file is loaded, all
forms are executed. However, note that file must
exactly match the program argument to the load
function.
|
eval-after-load library form | Function |
Arrange for form to be evaluated immediately after the Lisp
library of library has been read by the load function.
Note that library must exactly match the program argument
to load .
|
Obviously, not all features of the librep
environment are always
used. Autoloading allows libraries to only be loaded when they
are first required. This speeds up the initialisation process and may
save memory.
Functions which may be autoloaded have a special form in their symbol's function cell--an autoload form. This is a special kind of closure. When the function call dispatcher finds one of these forms it loads the program file specified in the form then re-evaluates the function call. The true function definition will then have been loaded and therefore the call may proceed as normal.
Autoload stubs may be created through the autoload
function.
autoload symbol file #!optional is-command | Function |
Installs an autoload form into the symbol symbol. It marks that when symbol is called as a function the lisp library file should be loaded to provided the actual definition of symbol. |
It is not necessary to call the autoload
function manually.
Simply prefix the definitions of all the functions that may be
autoloaded (i.e. the entry points to your module; not all the
internal functions.) with the magic comment ;;;###autoload
. Then
load the file into the Jade editor and invoke the add-autoloads
command, creating all the necessary calls to the autoload function in
the autoloads.jl
Lisp file (this file which lives in the Lisp
library directory is loaded when the environment is initialised).
;;;###autoload
preceding them have autoload forms
inserted into the autoloads.jl
file. Simply save this file's
buffer and the new autoloads will be used the next time Jade is
initialised.
It is also possible to mark arbitrary forms for inclusion in the
autoloads.jl
file: put them on a single line which starts with
the comment ;;;###autoload
call the command.
The unsaved autoloads.jl
buffer will become the current buffer.
;;;###autoload
(defun foo (bar) ;foo
is to be autoloaded
...
;;;###autoload (setq x y) ;Form to eval on initialisation
autoloads.jl
file which
are marked by the ;;;###autoload
comment in the current buffer.
The unsaved autoloads.jl
buffer will become the current buffer.
XXX these editor commands don't really belong here, but they'll do for now...
Features correspond to libraries of Lisp code. Each feature is
loaded separately. Each feature has a name, when a certain feature is
required its user asks for it to be present (with the require
function), the feature may then be used as normal.
When a feature is loaded one of the top-level forms evaluated is a call to
the provide
function. This names the feature and installs it into
the list of present features.
features | Variable |
A list of the features currently present (that is, loaded) in the
current module. Each feature is represented by a symbol. Usually the
print name of the symbol (the name of the feature) is the same as the
name of the file it was loaded from, minus any .jl or
.jlc suffix.
features => (info isearch fill-mode texinfo-mode lisp-mode xc) |
featurep feature | Function |
Returns true if the feature feature has been loaded into the current module. |
provide feature | Function |
Adds feature (a symbol) to the list of loaded features. A call
to this function is normally one of the top-level forms in a file.
;;;; maths.jl -- the
|
require feature #!optional file | Function |
Show that the caller is planning to use the feature feature (a symbol).
This function will check the features variable to see if feature
is already loaded, if so it will return immediately.
If feature is not present it will be loaded. If file is
given it specifies the first argument to the ;;;; physics.jl -- the When called interactively the symbol feature is prompted for. |
Features may also be provided by modules, for more details See Module Loading.
librep
contains a Lisp compiler as well as an interpreter; this
takes a Lisp form or program and compiles it into a byte-code
object. This byte-code object is a string of characters representing
virtual machine instructions, a vector of constants and some other
meta-information. The system also contains a byte-code interpreter;
this takes the compiled byte-codes and executes them by simulating the
virtual machine. This simulation will have exactly the same effect as
interpreting the original form or program.
One of the main reasons for compiling programs is to increase their efficiency. Compiled functions are likely to be more efficient than interpreted counterparts in all areas (space and time). For example:
user> (define (fib n) (if (<= n 2) 1 (+ (fib (- n 1)) (fib (- n 2))))) user> ,time (fib 30) 832040 Elapsed: 17.05572 seconds user> ,compile user> ,time (fib 30) 832040 Elapsed: 1.479007 seconds
--the compiled function is over an order of magnitude faster than the interpreted version.
compile-form form | Function |
This function compiles the Lisp form form into a byte-code form
which is returned.
(compile-form '(setq foo bar)) => (run-byte-code "F!" [bar foo] 2) |
compile-function function | Command |
This function replaces the uncompiled body of the function function (a symbol) with a compiled version, then returns function. |
compile-file file-name | Command |
This function compiles the file called file-name into a file of
compiled Lisp forms whose name is file-name with c appended
to it (i.e. if file-name is foo.jl it will be compiled to
foo.jlc ).
If an error occurs while the file is being compiled any semi-written file will be deleted. When called interactively this function will ask for the value of file-name. |
compile-directory directory #!optional force exclude | Command |
Compiles all the Lisp files in the directory called directory which
either haven't been compiled or whose compiled version is older than
the source file (Lisp files are those ending in .jl ).
If the optional argument force is true all Lisp files will be recompiled whatever the status of their compiled version. The exclude argument may be a list of filenames, these files will not be compiled. When this function is called interactively it prompts for the directory. |
compile-module module-name | Command |
Compiles all uncompiled function definitions in the module named
module-name (a symbol).
When called interactively the module name will be prompted for. |
run-byte-code byte-codes constants stack | Function |
Interprets the string of byte instructions byte-codes with
the vector of constants constants.
This function should never be called by hand. The compiler will produce calls to this function when it compiles a form or a function. |
There is a second form that byte-code objects can take: a vector whose
read syntax includes a preceding #
character is a byte-code
subr. These objects represent compiled Lisp functions and macros.
bytecodep arg | Function |
Returns true if arg is a byte-code subroutine. |
It is often useful to be able to give the compiler extra knowledge about the program forms that it is compiling. The language includes special declaration forms that have no effect when interpreted, but are meaningful to the compiler as it traverses the program.
declare clause... | Macro |
Offer the information contained in the clause... forms to the
compiler, which it may or may not use when compiling the program.
Each clause is a list, the first element of each clause is a symbol defining the type of declaration, the interpretation of any other elements in the clause depends upon the declaration type. The following table lists the syntax of all currently supported declaration types:
Declaration forms always evaluate to false. |
A second type of declaration is the eval-when-compile
form, it
allows Lisp forms to be evaluated only at compile-time.
eval-when-compile form | Macro |
This form tells the system that form should only be evaluated
when the containing code is being compiled.
The compiler knows to recognize forms of the pattern
When interpreted, |
Here are some tips for making compiled code run fast(er):
while
loops to traverse lists, use mapc
or tail recursion.
For example you might code a function to scan a list using iteration
through a while
loop:
(defun scan-list (lst elt) "Search the LST for an element similar to ELT. Return it if one is found." (catch 'return (while (consp lst) (when (equal (car lst) elt) (throw 'return elt)) (setq lst (cdr lst)))))
As well as obscuring what is actually happening, this will probably be fairly slow to execute. A more elegant solution is to use tail-recursion:
(defun scan-list (lst elt) (if (equal (car lst) elt) elt (scan-list (cdr lst) elt)))
An alternative idiom is to map an anonymous function over the list
using the mapc
function:
(defun scan-list (lst elt) (catch 'return (mapc (lambda (x) (when (equal x elt) (throw 'return elt))) lst) nil))
In fact, the compiler knows that calls to mapc
with a constant
lambda expression can be open-coded, so it will code the list traversal
directly using the virtual machine stack.
However, in most cases the execution time differences are likely to negligible.
member
, memq
, assoc
,
etc... can be used to search lists. Since these are primitives
written in C they will probably execute several times faster than an
equivalent Lisp function.
So the above scan-list
example can again be rewritten, this time
as:
(defun scan-list (lst elt) (car (member elt lst)))
cond
statements), so use whichever is the easiest
to understand.
(logor (lsh 1 6) x) ==> (logor 32 x)
It must be stressed that in some cases constants may not be
suitable; they may drastically increase the size of the compiled
program (when the constants are `big' objects, i.e. long lists) or even
introduce subtle bugs (since two references to the same constant may
not be eq
whereas two references to the same variable are always
eq
).
cons
, car
, cdr
, rplaca
, rplacd
,
nth
, nthcdr
, aset
, aref
, length
,
eval
, +
, *
, /
, %
, mod
,
lognot
, not
, logior
, logand
, logxor
,
equal
, eq
, =
, /=
, >
, <
,
>=
, <=
, 1+
, 1-
, -
, set
,
lsh
, zerop
, null
, atom
, consp
,
listp
, numberp
, stringp
, vectorp
,
throw
, boundp
, symbolp
, get
, put
,
signal
, return
, reverse
, nreverse
,
assoc
, assq
, rassoc
, rassq
, last
,
mapcar
, mapc
, member
, memq
, delete
,
delq
, delete-if
, delete-if-not
,
copy-sequence
, sequencep
, functionp
,
special-form-p
, subrp
, eql
, max
,
min
, filter
, macrop
, bytecodep
,
bind-object
.
if
, cond
, when
, unless
, let
, let*
,
catch
, unwind-protect
, error-protect
, with-buffer
,
with-window
, progn
, prog1
, prog2
, while
,
and
, or
, case
.
then the form is compiled. Otherwise it is just written to the output file in its uncompiled state.
If your program contains a lot of top-level forms which you know will
not be compiled automatically, consider putting them in a progn
block to make the compiler coalesce them into one byte-code form.
It is possible to disassemble byte-code forms; originally this was so I could figure out why the compiler wasn't working but if you're curious about how the compiler compiles a form it may be of use to you.
Naturally, the output of the disassembler is a listing in the assembly
language of the librep
virtual machine--it won't take a
byte-code form and produce the equivalent Lisp code!
disassemble-fun function #!optional stream | Command |
This function disassembles the compile Lisp function function. It
writes a listing to the output stream stream (normally the
value of the standard-output variable).
When called interactively it will prompt for a function to disassemble. |
When reading the output of the disassembler bear in mind that
librep
simulates a stack machine for the code to run on. All
calculations are performed on the stack, the value left on the stack
when the piece of code ends is the value of the byte-code form.
Here is a small example. Consider the fib
function given at the
start of this section:
(define (fib n) (if (<= n 2) 1 (+ (fib (- n 1)) (fib (- n 2)))))
After compilation and disassembly, the following is produced (but without the annotations):
Disassembly of #<closure fib>: 21 bytes, 1 constants, and (5,0,1) stack slots 0 required-arg ;requires a single parameter 1 dup 2 slot-set #0 ;store it in register 0 (r0) 3 pushi 2 4 le 5 jn 10 ;unless r0 <= 2, goto 10 8 pushi 1 9 return ;else, return 1 10 refg [0] fib 11 slot-ref #0 12 dec 13 call #1 ;push result of (fib (1- n)) 14 refg [0] fib 15 slot-ref #0 16 pushi 2 17 sub 18 call #1 ;push (fib (- n 2)) 19 add 20 return ;return the sum of the two calls
Datums are the mechanism by which librep
allows Lisp
programs to define new data types, such that these types are completely
distinct from the built-in data types (i.e. they match none of the
standard type predicates).
They also provide encapsulation, in that the data objects they provide are completely opaque, unless a pre-defined value is known (which was specified when the object was created, and is typically known only by the object's creator).
make-datum value key | Function |
Create and return a new datum object. It has the value value associated with it, and has type key. |
datum-ref arg key | Function |
If arg has type key, then return the value associated with it. Otherwise, an error is signalled. |
datum-set arg key value | Function |
If arg has type key, then set the value associated with it to be value. Otherwise, an error is signalled. |
has-type-p arg key | Function |
Return true if arg has type key. |
define-datum-printer key printer | Function |
Associate the function printer with all datum objects of type key. When any such object is printed, printer is applied to two arguments, the datum and the stream to which it should be printed (see Output Streams). |
A queue is an ordered set of objects, such that objects enter at one end of the queue (the tail), and leave from the other end of the queue (the head). The acts of entering and leaving a queue are often called enqueing and dequeueing.
librep
provides a straightforward queue implementation,
implemented by the rep.data.queues
module (see Modules).
make-queue | Function |
Create and return a new queue object. The queue will initially be empty. |
enqueue q arg | Function |
Add the object ARG to the tail of the queue q. |
dequeue q | Function |
Remove the object at the head of the queue q, and return it. If q is empty, an error is signalled. |
queue-empty-p q | Function |
Return true if the queue q is not empty. |
queuep arg | Function |
Return true if the object arg is a queue. |
queue->list q | Function |
Return a list of objects representing the contents of the queue q, with objects ordered from head to tail. Modifying the list structure causes undefined effects to the queue itself. |
queue-length q | Function |
Return the number of objects stored in the queue q. |
delete-from-queue q arg | Function |
Removes any occurrences of the object arg from the queue q. |
librep
provides a convenient means of defining structured data
types, these types are known as records. Each record is a
distinct data type, meaning that there will only be a single
type-predicate matching objects of any individual record type.
All definitions documented in this section are provided by the
rep.data.records
module (see Modules).
Record types are defined using the define-record-type
macro,
this in turn defines a number of functions implementing the type. These
functions include a constructor, a type predicate, and a user-defined
set of field-accessor and -modifier functions.
define-record-type type (constructor fields...) [predicate] (field accessor [modifier])... | Macro |
This macro creates a new record type storing an opaque object identifying the type in the variable named type. It then defines a function constructor with parameter list as specified by the fields..., and a predicate function called predicate if predicate is given. The fields of the record are defined by the sequence of
For each field a function accessor will be defined that when applied to an argument of the record type, returns the value stored in the associated field. If the modifier name is defined a function will be defined of that name, that when applied to a record and an object, stores the object into the associated field of the record. Note that the fields... may include all the standard lambda-list features (see Lambda Expressions), including keyword parameters and default values. |
Here is an example record definition:
(define-record-type :pare (kons x y) ; constructor pare? ; predicate (x kar set-kar!) ; fields w/ optional accessors (y kdr)) ;and modifiers
the variable :pare
is bound to the record type. Following this
definition, the record type could be used as follows:
(define x (kons 1 2)) (pare? x) => t (kar x) => 1 (set-kar! x 42) (kar x) => 42
By default record objects print as the name of their type in angle
brackets, e.g. for the above pare
type, each object would print
as the string #<:pare>
. This may be redefined using the
define-record-discloser
function.
define-record-discloser type discloser | Function |
Associate the function discloser with the record type type. When any record of this type is printed, discloser is applied to the object, it should return the value that will actually be printed. |
For the above example, the following could be used:
(define-record-discloser :pare (lambda (x) `(pare ,(kar x) ,(kdr x)))) (kons 'a 'b) => (pare a b)
Constructors for records with large numbers of fields often benefit
from using keyword parameters. For example the kons
record above
could be defined as follows (though this would make more sense if it
had more than two fields):
(define-record-type :pare (kons #!key (kar 1) (kdr 2)) pare? (kar kar set-kar!) (kdr kdr set-kdr!)) (kons #:kar 42) => (pare 42 2) (kons #:kdr 42) => (pare 1 42)
The rep.data.tables
module provides a flexible hash table
implementation (see Modules). Each hash table is represented by a
lisp object satisfying the tablep
predicate:
tablep arg | Function |
Return true if arg is a hash table. |
Hash tables may be created by using the make-table
and
make-weak-table
functions:
make-table hash-fun compare-fun | Function |
Create and return a new hash table. When storing and referencing keys it will use the function hash-fun to map keys to hash codes (positive fixnums), and the predicate function compare-fun to compare two keys (should return true if the keys are considered equal). |
make-weak-table hash-fun compare-fun | Function |
Similar to make-table , except that key-value pairs stored in the
table are said to be "weakly keyed". That is, they are only retained
in the table as long the key has not been garbage collected.
Unlike with tables created by the |
table-ref table key | Function |
Return the value stored in hash table table indexed by object key. Returns false if no such value exists. |
table-bound-p table key | Function |
Returns true if the hash table table contains a value associated with key. |
table-set table key value | Function |
Associate the value value with key in hash table
table. Returns value .
|
table-unset table key | Function |
Remove any value stored in table associated with key. |
table-walk function table | Function |
Call function function for every key-value pair stored in hash
table table. For each pair, the function is called with arguments
(key value) .
|
Several hash functions are also provided:
string-hash string | Function |
Return an integer representing the string string. |
symbol-hash symbol | Function |
Call (string-hash (symbol-name symbol)) .
|
eq-hash arg | Function |
Return a hash value representing object arg. The hash is generated from the address of the object. |
equal-hash arg | Function |
Return a hash value representing object arg. The hash is generated from the contents of the object. |
A guardian is a lisp object used to control when other data objects are recycled by the garbage collector (see Garbage Collection).7 The usual behaviour of the collector is to recycle objects as soon as they have no remaining references.
Guardians allow the programmer to detect when a specified object would be freed by the garbage collector, and to implement their own allocation policy. This can be useful, for example, with objects that have a high creation-overhead, and thus need to be cached for performance reasons.
make-guardian | Function |
This function allocates and returns a new guardian. Each guardian has a
list of data objects associated with it; some of which may have been
proved to have no remaining references to them (except from the
guardian system).
Calling the guardian object with a single argument, adds that value to the list of objects associated with that guardian. Calling the guardian with no arguments has one of two effects:
|
Note the use of the word "prove" in the above description, objects are only moved into a guardian's inaccessible set by the garbage collector.
Here is an example use of the guardian system:
;; create a new guardian object (setq G (make-guardian)) ;; create a lisp object (setq x (cons 'a 'b)) => (a . b) ;; protect the object using the guardian (G x) ;; remove the sole reference to the object (setq x nil) => () ;; invoke the garbage collector, this will ;; prove that the value added to the ;; guardian is no longer accessible (garbage-collect) ;; call the guardian to retrieve the ;; inaccessible value (G) => (a . b) ;; no more inaccessible values available (G) => ()
A stream is a Lisp object which is either a data sink (an output stream) or a data source (an input stream). All streams produce or consume sequences of 8-bit characters.
Streams are very flexible, functions using streams for their input and
output do not need to know the type of stream being accessed. For
example the Lisp reader (the read
function) takes an input
stream as its sole argument, it then reads characters from this stream
until it has parsed a whole object. This stream could be a file, a
function, or even a string; the read
function does not need to
differentiate.
streamp arg | Function |
Return true if arg is a stream. |
input-stream-p arg | Function |
Return true if arg is an input stream. |
output-stream-p arg | Function |
Return true if arg is an output stream. |
These are the possible types of input stream, for the functions which use them see Input Functions.
file
function
function should also be able to `unread' one character. When this happens the function will be called with one argument--the value of the last character read. The function should arrange it so that the next time it is called it returns this character. A possible implementation could be,
(defvar ms-unread-char nil "If true the character which was pushed back.") (defun my-stream (#!optional unread-char) (if unread-char (setq ms-unread-char unread-char) (if ms-unread-char (prog1 ms-unread-char (setq ms-unread-char nil)) ;; Normal case -- read and return a character from somewhere ...
nil
standard-input
.
It is also possible to use a string as an input stream. The string to
be read from must be applied to the make-string-input-stream
function
and the result from this function used as the input stream.
make-string-input-stream string #!optional start | Function |
Returns an input stream which will supply the characters of the string
string in order starting with the character at position start
(or from position zero if this argument is undefined).
(read (make-string-input-stream "(1 . 2)")) => (1 . 2) |
standard-input | Variable |
The input stream which is used when no other is specified or is false. |
Applications that embed librep
, or dynamically loaded
extensions, may provide further input stream types.
These are the different types of output stream, for the functions which use them see Output Functions.
file
function
process
t
()
standard-output
.
It is also possible to store the characters sent to an output stream in a string.
make-string-output-stream | Function |
Returns an output stream. It accumulates the text sent to it for the benefit
of the get-output-stream-string function.
|
get-output-stream-string string-output-stream | Function |
Returns a string consisting of the text sent to the string-output-stream
since the last call to get-output-stream-string (or since this stream
was created by make-string-output-stream ).
(setq stream (make-string-output-stream)) => ("" . 0) (prin1 keymap-path stream) => ("(lisp-mode-keymap global-keymap)" . 64) (get-output-stream-string stream) => "(lisp-mode-keymap global-keymap)" |
standard-output | Variable |
This variable contains the output stream which is used when no other is specified (or when the given output stream is false). |
standard-error | Variable |
This variable contains the output stream which is used when an error message is being reported. |
Applications that embed librep
, or dynamically loaded
extensions, may provide further output stream types.
read-char stream | Function |
Read and return the next character from the input stream stream. If the end of the stream is reached false is returned. |
read-line stream | Function |
This function reads one line of text from the input stream
stream, a string containing the line (including the newline
character which terminates the line).
If the end of stream is reached before any characters can be read false is returned, if the end of stream is reached but some characters have been read (but not the newline) these characters are made into a string and returned. Note that unlike the Common Lisp function of the same name, the newline character is not removed from the returned string. |
read stream | Function |
This function is the function which encapsulates the Lisp reader (see The Lisp Reader). It reads as many characters from the input stream stream as required to form the read syntax of a single Lisp object (see Read Syntax), this object is then returned. |
read-from-string string #!optional start | Function |
Reads one Lisp object from the string string, the first character
is read from position start (or position zero).
(read-from-string string start) == (read (make-string-input-stream string start)) |
write stream data #!optional length | Function |
Writes the specified character(s) to the output stream stream.
data is either the character or the string to be written. If
data is a string the optional argument length may
specify how many characters are to be written. The value returned
is the number of characters successfully written.
(write standard-output "Testing 1.. 2.. 3..") -| Testing 1.. 2.. 3.. => 19 |
copy-stream input-stream output-stream | Function |
This function copies all characters which may be read from
input-stream to output-stream. The copying process is not
stopped until the end of the input stream is read. Returns the number
of characters copied.
Be warned, if you don't choose the streams carefully you may get a deadlock which only an interrupt signal can break! |
print object #!optional stream | Function |
Outputs a newline character to the output stream stream, then
writes a textual representation of object to the stream.
If possible, this representation will be the read syntax of object. object is returned. (print '(1 2 3)) -| -| (1 2 3) => (1 2 3) |
prin1 object #!optional stream | Function |
Similar to print but no initial newline is output.
(prin1 '(1 2 3)) -| (1 2 3) => (1 2 3) (prin1 '|(xy((z]|) ;A strange symbol -| \(xy\(\(z\] => \(xy\(\(z\] |
prin1-to-string object | Function |
Returns a string containing the characters that prin1 would
output when it prints object.
(prin1-to-string '(1 2 3)) => "(1 2 3)" |
princ object #!optional stream | Function |
Prints a textual representation of object to the output stream
stream. No steps are taken to create output that read can
parse; in particular, no double-quote characters surround strings.
(princ "foo") -| foo => "foo" (princ '|(xy((z]|) -| (xy((z] => \(xy\(\(z\] |
Several variables may be used to control how objects are printed.
print-escape | Variable |
This defines which control characters print and prin1
will escape (using backslashes). Possible values are:
|
print-length | Variable |
This variable, if true, limits the number of elements printed from lists. |
print-level | Variable |
This variable, if true, limits the recursion depth when printing lists. |
format stream template #!rest values | Function |
Writes to a stream, stream, a string constructed from the
format string, template, and list of arguments values.
If stream is false the resulting string will be returned, not written to a stream. template is a template for the output string, any %[index$][flags][field-width]conversion index is an optional decimal number specifying exactly which of the values this conversion refers to (with the first at position one), and is usually used when translating messages; by default the next value is used. field-width is a positive decimal integer, defining the size in characters of the substitution output. conversion is a character defining how to convert the corresponding argument value to text. The default options are:
flags is a sequence of zero or more of the following characters,
The list of conversions can be extended through the
Note that the field-width and all flags currently have no effect
on the If stream isn't false (in which case the created string is returned) the value of stream is returned. (format nil "foo %S bar 0x%x" '(x . y) 255) => "foo (x . y) bar 0xff" (format standard-output "The %2$s is %1$s!" "purple" "dog") -| The dog is purple! => #<buffer *jade*> |
format-hooks-alist | Variable |
This variable is an association-list, each element being
(char . function) , defining extra conversions
for the format function.
If a conversion |
A hook allows you to wedge your own pieces of Lisp code into the
operation of other functions, enable the extension of that
functionality. These pieces of code are evaluated via the hook and the
result is available to the hook's caller. One hook has already been
encountered, the format-hooks-alist
variable (see Formatted Output).
Some hooks only allow a single piece of code to be hooked in. Usually a normally-undefined function is used; to install your hook defined a function with the name of the hook. When the hook is to be evaluated the function is called.
Generally the name of the hook's function will end in -function
.
An alternative scheme is to use a variable to store the hook, its value should be the function to call.
This is the standard type of hook, it is a variable whose value is a list of functions. When the hook is evaluated each of the functions will be called in turn.
The names of hooks of this type will normally end in -hook
.
add-hook hook function #!optional at-end | Function |
This function adds a new function function to the list of
functions installed in the (list) hook hook (a symbol).
If at-end is true the new function is added at the end of the hook's list of functions (and therefore will be called last when the hook is evaluated), otherwise the new function is added to the front of the list. text-mode-hook => (#<closure fill-mode-on>) (add-hook 'text-mode-hook my-function) => (#<closure my-function> #<closure fill-mode-on>) |
remove-hook hook function | Function |
This function removes the function function from the list of
functions stored in the (list) hook hook (a symbol).
All instances of function are deleted from the hook. |
There are actually three calling conventions for this type of hook,
differing in how many of the functions in the list actually get called.
In this simplest form, all functions are called. In an
and
type hook, functions are only invoked while all others have
returned true. As soon as the first function in the hook returns
false, no others will be called. Finally, an or
type hook
aborts when a function returns a true result.
call-hook hook arg-list #!optional type | Function |
Call the hook named by the symbol hook, passing all functions the arguments in the list arg-list. Note that hook may also be the actual list of functions to call. type defines how the return values of each function in the hook
are treated. If type is false they are ignored, if
type is the symbol In all cases the value returned by the last-evaluated function is returned. |
librep
allows you to manipulate files in the operating system's
filing system; a special type of Lisp object, a file object, is
used to represent files which have been opened for reading or writing
(through the streams mechanism, see Streams).
Names of files are represented by strings, the syntax of file names is
defined by the underlying operating system: librep
simply treats
it as a string.
A file name is a string identifying an individual file (or directory) in the filing system (i.e. the disk). The exact syntax of file names depends on the operating system. There are several functions for manipulating file names.
file-name-absolute-p file-name | Function |
Returns true when file-name is not specified relative to the current directory. |
file-name-directory file-name | Function |
This function returns the directory part of the file name string
file-name. This is the substring of file-name defining the
directory containing the file.
(file-name-directory "/tmp/foo") => "/tmp/" (file-name-directory "foo") => "" (file-name-directory "foo/bar/") => "foo/bar/" |
file-name-nondirectory file-name | Function |
Returns the substring of the file name file-name which is
not the directory part.
(file-name-nondirectory "/tmp/foo") => "foo" (file-name-nondirectory "foo") => "foo" (file-name-nondirectory "foo/bar/") => "" |
file-name-as-directory file-name | Function |
Returns a string through which the item in the file system named by
file-name can be referred to as a directory.
(file-name-as-directory "./foo") => "./foo/" (file-name-as-directory "./foo/") => "./foo/" |
directory-file-name directory-name | Function |
Returns a string through which the directory named by
directory-name can be referred to as a file.
(directory-file-name "./foo/") => "./foo" (directory-file-name "./foo") => "./foo" |
expand-file-name file-name #!optional base-dir | Function |
Expands file-name assuming that it specifies a file relative to
base-dir. If base-dir is undefined it is taken as the
current value of the default-directory variable. While expanding
the file name, any obvious simplifications will be performed (e.g. on
Unix the removal of "." and ".." where possible).
Note that the returned file name will only be absolute if one of the following conditions is met:
(expand-file-name "foo" "./bar") => "bar/foo" Note for file handler implementors: when a handler is called for the
|
canonical-file-name file-name | Function |
This function returns the canonical name of the file referred to by the
string file-name. The canonical name of a file is defined such
that two files can be compared simply by comparing their canonical
names; if the names match, they refer to the same file.
(Note that the opposite isn't always true, if two canonical names don't match the files could still be the same, for example via hard links. On most operating systems, symbolic links will be expanded where possible. (canonical-file-name "foo") => "/home/john/src/librep/man/foo" |
local-file-name file-name | Function |
librep supports extensible file handling (see File Handlers), so file names may refer to files not residing in the
system's local file structure, and thus which are unavailable to other
programs.
This function returns either the absolute name of the file file-name, if it is found in the local system, or false, if the file does not. (local-file-name "foo") => "/home/john/src/librep/man/foo" (local-file-name "/john@tango:foo") => () |
make-temp-name | Function |
This function returns the name of a file which, when created, may be used
for temporary storage. Each time this function is called a unique name is
computed.
(make-temp-name) => "/tmp/00088aaa" (make-temp-name) => "/tmp/00088baa" |
default-directory | Variable |
This variable names the current working directory. All relative file names are interpreted starting from this location in the file system. |
A file object is a Lisp object which represents an open file in the filing system. Any file object may be used as a stream (either input or output) to access the contents of the file (see Streams).
filep object | Function |
This function returns true when its argument is a file object. |
open-file file-name mode | Function |
This function opens the file called file-name (see File Names) and returns the new file object.
The mode argument is a symbol defining the access modes used to open the file with, the options are:
|
The three standard I/O streams are also available as file handles.
stdin-file | Function |
Return a file object representing the interpreters standard input. |
stdout-file | Function |
Return a file object representing the interpreters standard output. |
stderr-file | Function |
Return a file object representing the interpreters standard error. |
Attempting to close any of these files will result in the associated
stream being connected to /dev/null
.
The easiest way to close a file is simply to eliminate all references to it, subsequently the garbage collector will close it for you. It is better to close files explicitly though since only a limited number of files may be opened concurrently.
close-file file-object | Function |
This function closes the file pointed to by the file object
file-object.
Subsequently, any stream accesses file-object are illegal and will signal an error. |
seek-file file #!optional offset where | Function |
When called as (seek-file file) , returns the distance in
bytes from the start of the file that the next character would be read
from.
When called as
Note that not all files may be seekable; if |
flush-file file | Function |
This function flushes any buffered output to the file object file to disk. |
file-binding file | Function |
Returns the name of the file which the file object file is
currently bound to. Returns false if the file is currently unbound
(i.e. close-file was called on it).
|
The next three functions are used when non-local files are being accessed. See File Handlers for more details.
file-bound-stream file | Function |
If the file object file doesn't refer to a file in the local filing system, return the stream that it is bound to (allowing the file's contents to be accessed), this may or may not be another file object. |
file-handler-data file | Function |
Return the file-handler-specific data associated with the file object file. |
set-file-handler-data file data | Function |
Set the handler-specific data of file object file to data. This should only be done by the handler owning the file. |
It's also possible to register a callback function to be invoked when input is available on a file,
set-input-handler local-file function | Function |
Arrange for function to be called whenever pending input is
available on local-file, a file object bound to a file in the
local file space.
Note that this makes local-file subsequently do non-blocking input. This function is normally only useful when local-file represents a pipe or socket. |
A number of functions exist which when given the name of a file return one of the attributes relating to that file.
file-exists-p file-name | Function |
Returns true when a file file-name exists. |
file-regular-p file-name | Function |
Returns true when the file file-name is a `normal' file. This means that it isn't a directory, device, symbolic link or whatever. |
file-directory-p file-name | Function |
Returns true when the file file-name is a directory. |
file-symlink-p file-name | Function |
Returns true when the file file-name is a symbolic link. |
file-readable-p file-name | Function |
Returns true when the file file-name is readable. |
file-writable-p file-name | Function |
Returns true when the file file-name is writable. |
file-owner-p file-name | Function |
Returns true when the ownership of the file file-name is the same as that of any files written by the editor. |
file-size file-name | Function |
Returns the number of bytes stored in the file named file-name. |
file-nlinks file-name | Function |
Returns the number of hard links pointing to the file file-name. If file-name has only one name the number will be one. |
file-modes file-name | Function |
This function returns the access permissions of the file file-name. This will be an integer whose format is undefined; it differs from operating system to operating system. |
file-modes-as-string file-name | Function |
Returns a ten-character string describing the attibutes of the file
called file-name
(file-modes-as-string ".") => "drwxr-sr-x" |
set-file-modes file-name modes | Function |
This function sets the access permissions of the file file-name to
the integer modes (as returned by the file-modes function).
|
file-modtime file-name | Function |
Returns the system time at the last modification to the file file-name, this will be in the usual timestamp format, See Timestamps. |
file-newer-than-file-p file-name1 file-name2 | Function |
This function returns true if the file file-name1 was modified more recently than the file file-name2 was. |
delete-file file-name | Command |
This function deletes the file called file-name. When called interactively file-name is prompted for. |
rename-file file-name new-name | Command |
This function attempts to change the name of the file new-name
to new-name.
This won't work from one file system to another or if a file called new-name already exists, in these cases an error is signalled. This prompts for its arguments when called interactively. |
copy-file file-name destination-name | Command |
Creates a new copy of the file file-name with the name
destination-name.
The access modes of the new file will be the same as those of the original file. The arguments are prompted for when this function is called interactively. |
make-directory directory-name | Command |
Create a new directory called directory-name. |
delete-directory directory-name | Command |
Delete the directory called directory-name. This only succeeds if the directory in question is empty, otherwise an error is signalled. |
directory-files directory-name | Function |
Returns a list of the names of all items in the directory whose name is
directory-name. The names in the list will be relative to the
directory directory-name.
(directory-files "/tmp/foo" => ("bar" "subdir" "xyz" "." "..") |
make-symlink name contents | Function |
Create a symbolic link called name, containing the string contents. |
read-symlink name | Function |
Return the string that is the contents of the symbolic link called name. Signals an error if no such link exists. |
As noted earlier, librep
supports virtual files; that is it
allows file names to be accessed that don't reside on the local filing
system, or aren't normally valid as file names. This is achieved
through the use of file handlers, Lisp functions that have
signalled that they should be used to redirect all accesses to files
whose names match a particular regular expression (see Regular Expressions).
For example, there is a convention under Unix that a user's home
directory can be accessed via the file name ~
, even though there
is no such support from the operating system itself. So a file handler
can be (and has been) written that recognises all file names starting
with a tilde, translating them to the actual file in the file system.
file-handler-alist | Variable |
This variable contains a list of file handler declarations, each one of
the form (regexp . function) . Whenever a file
operation is performed on a file whose name matches regexp,
function is invoked to perform the action. The function is called
as (function operation args...) , where
operation and args are from the original call.
For example if the Thus if a form |
The list of operations that may be redirected to a file handler is:
file-name-absolute-p
, expand-file-name
,
local-file-name
, canonical-file-name
,
file-name-nondirectory
, file-name-directory
,
file-name-as-directory
, directory-file-name
,
open-file
, close-file
, flush-file
,
seek-file
, write-buffer-contents
,
read-file-contents
, insert-file-contents
,
delete-file
, rename-file
, copy-file
,
copy-file-to-local-fs
, copy-file-from-local-fs
,
make-directory
, delete-directory
, file-exists-p
,
file-regular-p
, file-readable-p
, file-writable-p
,
file-directory-p
, file-symlink-p
, file-owner-p
,
file-nlinks
, file-size
, file-modes
,
file-modes-as-string
, set-file-modes
,
file-modtime
, directory-files
,
make-symlink
, read-symlink
.
There are several undefined functions in this list. The
write-buffer-contents
, read-file-contents
, and
insert-file-contents
pertain to the Jade text editor. The other
two are defined as follows.
copy-file-to-local-fs file-name local-name | Operation |
Called when copying files between file handlers, this operation should copy the file matching the handler file-name, to the file on the local file system local-name. |
copy-file-from-local-fs local-name file-name | Operation |
Called when copying files between file handlers, this operation should copy the local file file-name to the file matching the handler file-name. |
To prevent infinite recursion, while a particular operation is being processed by a file handler, that operation may not be passed back to the same handler.
To allow file handlers to handle the open-file
operation, it is
possible to create file handles from arbitrary streams.
make-file-from-stream file-name stream handler | Function |
Return a new file object that refers to the logical file called file-name, that is not in the local filing system. All access to the file object will be directed through the stream object stream, and the file handler function handler. |
An alternative method of opening remote files is to use a temporary
file in the local file system with either one (read
or
write
modes), or two (append
mode) synchronisations with
the remote system. This is the method used by the FTP remote file
backend (see the next section). It has the advantage of simplifying the
seek-file
operation.
Since one of the intentions for file handlers is to allow remote files
to be accessed, a common method of providing new methods of doing this
has been implemented, in the remote.jl
Lisp library.
Accessing a file name matching the regular expression:
^/(([a-zA-Z0-9._-]+)@)?([a-zA-Z0-9._-]+):
for example /john@host.com:file
refers to a file called
file
owned by the user john
, on the system
host.com
.
If no username is specified explicitly, two variables are used to select the user:
remote-host-user-alist | Variable |
An alist mapping host regexps to the default user name to use for remote file connections to that host. |
remote-default-user | Variable |
User name to use for remote file connections when otherwise unspecified. By default the current user name on the local system. |
Two variables control how individual hosts are matched to methods of accessing files.
remote-auto-backend-alist | Variable |
An alist of (host-regexp . backend-type) mapping
host names to methods of accessing remote files.
|
remote-default-backend | Variable |
A symbol defining the method to use for otherwise unselected hosts. |
A method of accessing files, or a backend is a symbol whose
remote-backend
property names a function to call when files need
to be accessed. For example the ftp
backend is initialised as:
(put 'ftp 'remote-backend remote-ftp-handler)
The backend function is called as (function
split-name operation args)
. The split-name is
a three-element list, (user-or-nil host file)
defining the file to be accessed. The other options are as usual.
Further details can be found in the remote.jl
,
remote-ftp.jl
and remote-rcp.jl
Lisp source files.
The ftp
backend is currently the most well-developed, several
functions and variables may be used to customise its behaviour.
remote-ftp-add-passwd user host passwd | Function |
Add the string passwd as the password for the FTP session connecting to user@host. |
remote-ftp-show-messages | Variable |
When true (the default), messages are displayed as FTP commands are executed. |
remote-ftp-display-progress | Variable |
When true (the default) display progress of FTP transfers. |
remote-ftp-anon-users | Variable |
A regular expression matching the user names for "anonymous" FTP sessions. |
remote-ftp-anon-passwd | Variable |
The string to send as the passwd of an anonymous FTP session. By default the current uses email address. |
There is a problem with the ftp
backend however; due to
limitations in the FTP protocol, not all librep
file operations
are supported, with the most obvious exception being the
make-symlink
function.
When this is a problem it may be possible to use rep's custom file
transfer protocol. If it is possible to use rsh
to connect to
the remote host in question, then the rep
backend may be used.
The rep-remote
program distributed with librep
must exist
on the remote host, this is executed via rsh
and provides a
protocol for executing all of librep
's file operations on that
host. See the lisp/remote-rep.jl
file in the distribution for
more details.
When running on a Unix-style operating system librep
allows you
to launch and control an arbitrary number of subprocesses. These
subprocesses can run either synchronously or asynchronously in respect
to the Lisp system; data can be sent to the stdin
channel and
any output from the process is automatically written to a specified
Lisp output stream.
A process object is a type of Lisp object used to provide a link between a `physical' process running in the operating system and the Lisp system. Each process object consists of a number of values (references to other Lisp objects); these values are used when the object is used to run a subprocess.
Process objects which aren't currently being used to run a subprocess store the exit value of the last subprocess which was run on that object.
processp object | Function |
This function returns true when its argument is a process object. |
The programmer-accessible components of a process object are,
stdout
channel is copied to this
output stream. See Process I/O.
stderr
channel is copied to this
output stream. Unless explicitly specified error output goes to the
stdout
stream. See Process I/O.
make-process #!optional output-stream state-function directory program args | Function |
This functions creates and returns a new process object. No subprocess
will be started.
The optional arguments are used to define the values of the components of the new process object, any undefined components will be set to default or null values. |
For each component of a process object two functions exist; one to read the component's value in a specific process object, the other to set the component's value.
process-prog process | Function |
Returns the value of the program name component of the process object process. |
set-process-prog process prog-name | Function |
Sets the value of the program name component of the process object process to the string prog-name, then returns prog-name. |
process-args process | Function |
Returns the value of the program arguments component of the process object process. |
set-process-args process arg-list | Function |
Sets the value of the program arguments component of the process object process to the list arg-list, then returns arg-list. |
process-dir process | Function |
Returns the value of the directory component of the process object process. |
set-process-dir process directory | Function |
Sets the value of the directory component of the process object process to the string directory, then returns directory. |
process-environment | Variable |
This is a list of environment variable definitions, as well as being
used by the setenv and getenv functions
(see Environment Variables), it also provides the environment of
all started subprocesses.
(car process-environment) => "LOGNAME=john" |
active-processes | Function |
Returns a list containing all active (i.e. running or stopped) process objects. |
An asynchronous process is one that runs in parallel with Lisp
evaluation, basically this means that once the subprocess has been
started (by the start-process
function) librep
will carry
on as normal.
The event loop checks for output from asynchronous processes, any found
is copied to the process' output stream, and calls the the process' state
change function when necessary (see Process States). Alternatively
the accept-process-output
function can be called to explicitly
allow output to be processed.
When using asynchronous processes you have a choice as to the Unix
mechanism used to connect the stdin
, stdout
and
stderr
streams of the subprocess to librep
's process.
The two options currently available are pipes or pseudo-terminals; in
general pseudo-terminals should only be used to provide a direct
interface between the user and a process (i.e. the *shell*
buffer) since they allow job control to work properly. At other times
pipes will be more efficient and are used by default. However, there
are cases where the buffering characteristics of pipes mean that ptys
must be used.
start-process #!optional process program #!rest args | Function |
This function starts an asynchronous subprocess running on the process
object process. If process is undefined a new process
object is created (by calling the function make-process with all
arguments undefined).
The function always returns the process object which the subprocess has
been started on. If for some reason the subprocess can't be created an
error of type The optional argument program is a string defining the name of
the program to execute, it will be searched for in all the directories
in the When defined, the optional arguments overrule the values of the related components of the process object. The following example runs the (let ((process (make-process standard-output))) (start-process process "ls" "-s")) |
Note that when librep
exits it kills all of its asynchronous
subprocesses which are still running without warning.
process-connection-type process | Function |
Returns the value of the connection type component of the process object
process. See the documentation of the set-process-connection-type
function for the values this may take.
|
set-process-connection-type process symbol | Function |
Sets the value of the connection type component of the process object
process to symbol, then returns symbol.
symbol should be one of the following symbols,
|
Note that currently only the pipe
connection type allows the
normal and error output streams of the process to be separated.
When a synchronous process is started librep
waits for it
to terminate before continuing; they are usually used when a Lisp
program must invoke an external program as part of its function, i.e.
the auto-compression feature runs the compression program gzip
synchronously when it needs to compress a buffer.
Unlike asynchronous processes their is no choice between pipes and
pseudo-terminals for connecting to a subprocess. Instead, it is
possible to link the stdin
channel of a synchronous process to a
named file.
call-process #!optional process input-file-name program #!rest args | Function |
This function starts a process running on the process object
process. If process is undefined a new process object is
created by calling the make function.
If defined, the string input-file-name names the file to connect
to the standard input of the subprocess, otherwise the subprocess'
input comes from the null device ( The optional arguments program and args define the name of
the program to invoke and any arguments to pass to it. The program will
be searched for in all directories listed in the
If any of the optional parameters are unspecified they should have been set in the process-object prior to calling this function. After successfully creating the new subprocess, this function simply
copies any output from the process to the output stream defined by the
output stream component of the process object. When the subprocess
exits its exit-value is returned (an integer). Note that the exit-value
is the value returned by the If, for some reason, the new subprocess can't be created an error of
type |
The following function definition is taken from the gzip.jl
file, it shows how the call-process
function can be used to
uncompress a file into a buffer (for Jade).
;; Uncompress FILE-NAME into the current buffer (defun gzip-uncompress (file-name) (let ((proc (make-process (current-buffer)))) (message (concat "Uncompressing `" file-name "'") t) ;; gunzip can do .Z files as well (unless (zerop (call-process proc nil "gunzip" "-c" file-name)) (signal 'file-error (list "Can't gunzip file" file-name)))))
The user is able to interrupt synchronous subprocesses (for example if
they seem to have got wedged somehow). Each time a user-interrupt is
received by librep
(i.e. the INT
signal), a stronger
signal is sent to the subprocess. First an interrupt signal, then a
termination signal, before finally a non-ignoreable quit signal is
sent.
It is only possible for lisp programs to explicitly send input data to
asynchronous processes (by the time it's possible to call a
function to send data to a synchronous process, the process will
already have terminated!). Simply use the process object which an
asynchronous process is running on as a normal Lisp input stream, any
strings or characters written to the stream will immediately be copied
to the stdin
channel of the subprocess.
With synchronous processes, the only control over input data possible
is by giving the call-process
function the name of a file
containing the subprocess' input data.
Output data from subprocesses is handled the same way by both asynchronous and synchronous processes: it is simply copied to the stream defined by the output stream component of the subprocess' process object.
process-output-stream process | Function |
Returns the value of the output stream component of the process object process. |
set-process-output-stream process stream | Function |
Sets the value of the output stream component of the process object process to the stream stream, then returns stream. |
By default the stdout
and stderr
streams are combined,
use the set-process-error-stream
function to separate them.
(Note that this currently only works with pipe
connection
types.)
process-error-stream process | Function |
Returns the value of the error stream component of the process object process. |
set-process-error-stream process stream | Function |
Sets the value of the error stream component of the process object process to the stream stream, then returns stream. |
Output from asynchronous subprocesses (this includes changes of state
as well as stream output) is only propagated at well-defined times.
Either when in the read stage of the read-eval-print, or input, loop,
or when the accept-process-output
or sit-for
functions
are called.
accept-process-output #!optional seconds milliseconds | Function |
Wait seconds plus milliseconds for output from any asynchronous subprocesses. If any arrives, process it, then return false. Otherwise return true. If either of the arguments is undefined, they count as zero in the addition. |
sit-for #!optional seconds milliseconds | Function |
Wait for input to arrive and be processed. No more than seconds
seconds plus milliseconds milliseconds will be waited. If at the
end of this time no input has arrived, return true. Otherwise
return false if input was found.
Note that this function is only distinct to
|
See Streams.
Each process object has a state associated with it; this depends on the status of the subprocess currently running on the process object (or not as the case may be).
The possible states are,
Predicates exist which test whether a given process object is in one of these states.
process-running-p process-object | Function |
Returns true when process-object is in the running state. |
process-stopped-p process-object | Function |
Returns true when process-object is in the stopped state. |
process-in-use-p process-object | Function |
Returns true when process-object is not in the unused state. |
The following two functions are used to stop and then subsequently continue a process running.
stop-process process-object #!optional whole-group | Function |
This function suspends execution of the subprocess running on the
process object process-object.
If whole-group is true all subprocesses in the process group of process-object are stopped. |
continue-process process-object #!optional whole-group | Function |
Use this function to continue a subprocess executing after it has been
stopped (by the stop-process function).
If whole-group is true all subprocesses in the process group of process-object are continued. |
The state change function component of a process object defines a function which will be called each time the state of the process object changes. If your program needs to be informed when an asynchronous process terminates this function is the way to do it.
process-function process | Function |
Returns the value of the state change function component of the process object process. |
set-process-function process function | Function |
Sets the value of the state change function component of the process object process to the function function, then returns function. |
interrupt-process process-object #!optional whole-group | Function |
Sends the SIGINT signal to process-object.
|
kill-process process-object #!optional whole-group | Function |
Sends the SIGKILL signal to the process-object.
|
Note that the functions stop-process
and continue-process
also send signals to the subprocess.
signal-process process signal #!optional whole-group | Function |
Send the signal signal to the process process; if
whole-group is true the signal is also sent to all
processes in the process group of process.
process may be either a Lisp process object, or an integer
defining the pid of the process to signal (not necessarily started by
signal may either be an integer defining the actual signal
number, or a symbol naming the signal. All names are as usual but with
the preceding Returns true if the signal was sent successfully. |
As with the UNIX kill
system call, signal-process
may
also be used to test whether a process with a particular pid is
currently active, by using a signal with value zero.
process-id process-object | Function |
This function returns the operating-system identifier associated with the subprocess currently running on the process object process-object. |
process-exit-value process-object | Function |
Returns the integer representing the return code of the last subprocess
to be run on process-object.
If no subprocess has been run on process-object, process-object is currently in the running state or the last subprocess exited abnormally (i.e. from a terminal signal) false is returned. |
process-exit-status process-object | Function |
This function returns the integer that was the exit status of the last
subprocess which was run on the process object process-object.
Note that the exit status is not the value given to the If no process has been run on process-object, or the process is currently in the running state false is returned. |
Regular expressions (or regexps) are a powerful method of
matching patterns in strings. librep
uses the regexp(3)
implementation by Henry Spencer, with some modifications that I have
made. It comes with this banner:
Copyright (c) 1986 by University of Toronto.
Written by Henry Spencer. Not derived from licensed software.Permission is granted to anyone to use this software for any purpose on any computer system, and to redistribute it freely, subject to the following restrictions:
- The author is not responsible for the consequences of use of this software, no matter how awful, even if they arise from defects in it.
- The origin of this software must not be misrepresented, either by explicit claim or by omission.
- Altered versions must be plainly marked as such, and must not be misrepresented as being the original software.
The syntax of a regular expression is as follows (this is adapted from the manual page):
A regular expression is zero or more branches, separated by
|
. It matches anything that matches one of the branches.
A branch is zero or more pieces, concatenated. It matches a match for the first, followed by a match for the second, etc.
A piece is an atom possibly followed by *
, +
, or
?
. An atom followed by *
matches a sequence of 0 or more
matches of the atom. An atom followed by +
matches a sequence of
1 or more matches of the atom. An atom followed by ?
matches a
match of the atom, or the null string.
An atom is a regular expression in parentheses (matching a match for
the regular expression), a range (see below), .
(matching
any single character), ^
(matching the null string at the
beginning of the input string), $
(matching the null string at
the end of the input string), one of the strings \s
, \S
,
\w
, \W
, \d
, \D
, \b
, \B
, or a
\
followed by a single character (matching that character), or a
single character with no other significance (matching that character).
A range is a sequence of characters enclosed in []
. It
normally matches any single character from the sequence. If the
sequence begins with ^
, it matches any single character
not from the rest of the sequence. If two characters in the
sequence are separated by -
, this is shorthand for the full list
of ASCII characters between them (e.g. [0-9]
matches any decimal
digit). To include a literal ]
in the sequence, make it the
first character (following a possible ^
). To include a literal
-
, make it the first or last character.
Also, any of the *
, +
or ?
operators can be
suffixed by a ?
character (i.e. *?
, +?
,
??
). The meaning of the operator remains the same but it becomes
non-greedy. This means that it will match the smallest
number of characters satisfying the regular expression, instead of the
default behaviour which is to match the largest.
The backslash-introduced atoms have the following meanings:
\s
\S
\w
\W
\d
\D
\b
\w
and \W
characters (in any order).
\B
\w
and
\W
characters.
Some example legal regular expressions could be:
ab*a+b
a
followed by zero or more b
characters, followed by
one or more a
characters, followed by a b
. For example,
aaab
, abbbab
, etc...
(one|two)_three
one_three
or two_three
.
^cmd_[0-9]+
^cmd_\d+
cmd_
followed by one or more digits, it must start at the
beginning of the line.
quote-regexp string | Function |
Return a version of string, such that when used as a regexp, it
will match the original contents of string verbatim, and nothing
else. This involves quoting regexp meta-characters.
(quote-regexp "abc") => "abc" (quote-regexp "a+c") => "a\\+c" |
string-match regexp string #!optional start ignore-case | Function |
Returns true if the string string matches the regular
expression regexp. The string matches if executing the regexp at
any position in the string succeeds.
When defined, start is the index of the first character to start matching at (counting from zero). When ignore-case is true the case of matched strings are ignored. Note that character classes are still case-significant. (string-match "ab+c" "abbbc") => t (string-match "ab+c" "xxxabbbcyyy") => t |
string-looking-at regexp string #!optional start ignore-case | Function |
Similar to string-match , but only returns true if
string matches regexp starting at the character at index
start in the string (or the first character if start is
undefined).
(string-looking-at "ab+c" "abbbc" 0) => t (string-looking-at "ab+c" "xxxabbbcyyy" 0) => () (string-looking-at "ab+c" "xxxabbbcyyy" 3) => t |
match-start #!optional n | Function |
Returns the position at which the n'th parenthesised expression
started in the last successful regexp match. If n is false
or zero the position of the start of the whole match is returned
instead.
When matching strings, all positions are integers, with the first character in the string represented by zero. However, extensions that allow regexps to be matched against other textual inputs may return different position values. (string-match "x*(foo|bar)y" "xxxbary") => t (match-start 1) => 3 |
match-end #!optional n | Function |
Similar to match-start , but returns the position of the
character following the matched item.
(string-match "x*(foo|bar)y" "xxxbary") => t (match-end 1) => 6 |
A common use of regular expressions is to match a string, then replace certain portions of the string with other text.
expand-last-match template | Function |
Expand the template substituting the parenthesised expressions
from the most recent successfully matched regular expression.
template may contain the following substitution-inducing escape sequences:
(string-match "x*(foo|bar)y" "xxxbary") => t (expand-last-match "test-\\1-ing") => "test-bar-ing" Note that double backslashes are required due to the read syntax of strings (see Strings). |
This section describes how time and date values are handled in
librep
.
As in UNIX, librep
measures time as the number of seconds since
January 1st, 1970 (known as the epoch). However, since integers
only store 30 bits of information, timestamps can not be kept as single
numbers. Instead a pair of integers is used, stored in a cons cell.
The first integer records the number of whole days since the epoch, the second records the number of seconds since the start of the day (in universal time).
current-time | Function |
Return the number of seconds since the epoch, in a cons-cell.
(current-time) => (10744 . 61063) |
fix-time timestamp | Function |
Ensure that the two parts of timestamp (a pair or integers) are consistent, simply that the number of seconds is less than the number of seconds in a whole day. If not, the timestamp is adjusted to fix this. |
time-later-p timestamp-1 timestamp-2 | Function |
Returns true if timestamp-1 is later than timestamp-2. |
On the plus side, this scheme won't wrap around as quickly as UNIX's
time_t
will ;-)
Given a timestamp value it is possible to format it as a string, in many different formats.
current-time-string #!optional timestamp format | Function |
Return a string defining timestamp according to the string
format. If timestamp is undefined, the current time is
used.
The format string may include any of the formatting characters
from the C library's (current-time-string) => "Wed Jun 2 18:07:53 1999" Some of the possible formatting substitutions include (this is copied from the GNU libc manual, see (libc)Formatting Date and Time):
(current-time-string nil "%Y-%m-%d") => "1999-06-02" |
The date
Lisp library provides rudimentary support for parsing
date and time descriptions to their individual components, and to
timestamps. Evaluate the form (require 'date)
to load this
library.
parse-date string #!optional start | Function |
Returns a vector encoding the date described by string. If
start is defined, it specifies the index of the character in the
string to start parsing from.
Each element of the vector contains a separate component of the overall point in time described by the string. The indices of these elements are defined by the following constants:
(current-time-string) => "Wed Jun 2 18:37:17 1999" (parse-date (current-time-string)) => ["Wed" 2 "Jun" 6 1999 18 37 17 0 (10744 . 67037)] (parse-date "1999-06-02") => ["Tue" 2 "Jun" 6 1999 0 0 0 0 (10744 . 0)] (parse-date "June 6, 1999") => ["" 0 "Jun" 6 1999 0 0 0 0 (10742 . 0)] (aref (parse-date "June 6, 1999") date-vec-epoch-time) => (10742 . 0) |
XXX provide more information on accepted formats, outputs for incomplete descriptions, etc...
librep
has support for internationalisation (or i18n) of text
messages, using the GNU gettext
implementation (see Top), a run-time library
managing the mapping between text strings in the programmer's native
language and in the language of the end user.
Three functions are provided to access the message catalogues
maintained by GNU gettext
. Import the rep.i18n.gettext
module to load them.
_ string | Function |
Attempt to find a native language equivalent of string. If no
equivalent is found the original string is returned.
Note that this function is always defined, even if the |
bindtextdomain domain directory | Function |
Tell gettext that message catalogues for message domain
domain (a string) can be found under the directory called
directory.
|
textdomain domain | Function |
Note that any strings that are to be translated in the future (until
the next call to textdomain ) are in the domain called
domain (a string).
|
The usual method of constructing message catalogue templates
(.pot
files) is to run xgettext
on the C source files of
the program (that have been annotated for i18n). librep provides the
rep-xgettext
program to perform the same task for files of Lisp
code.
operating-system | Variable |
A symbol naming the current operating system. The only current option
is unix .
|
system-name | Function |
This function returns a string naming the host that the interpreter is running on. When possible this be a fully-qualified name (i.e. including the domain) |
rep-build-id | Variable |
A string describing the environment under which librep was
built. This will always have the format date by
user@host, for arch. .
rep-build-id => "Mon May 17 1999 by john@tizer.dcs.warwick.ac.uk, for sparc-sun-solaris2.6." |
rep-version | Variable |
A string describing the current release of librep .
rep-version => "1.0" |
user-login-name | Function |
This function returns a string containing the login name of the user.
(user-login-name) => "john" |
user-full-name #!optional real-name | Function |
This function returns a string containing the `real' name of the user; the
format of the string will depend on the host system.
If real-name is a string, it defines the name that will be returned by subsequent calls to this function. (user-full-name) => "John Harper" |
user-home-directory #!optional user | Function |
This function returns the home directory of the user whose login name is
user, or the current user if user is undefined. The
returned string will be as returned by file-name-as-directory
(i.e. terminated by a / character under UNIX)
(user-home-directory) => "/home/john/" |
getenv variable-name | Function |
This function returns the value (a string) of the environment variable
called variable-name. If the specified variable doesn't exist
false is returned.
(getenv "OSTYPE") => "Linux" |
setenv variable-name new-value | Function |
This function sets the value of the environment variable called variable-name to new-value. new-value can either be a string containing the new contents of the variable or false, in which case the environment variable is deleted. |
unsetenv variable-name | Function |
Deletes any variable in process-environment named
variable-name.
|
See also Process Objects for the description of the
process-environment
variable.
translate-string string map | Function |
Applies the map to each character in the string. map
is also string, each character represents the translation for an ASCII
character of that characters position in the string. If the string is
less than 256 chars long any undefined characters will remain
unchanged.
For example, if string contains the character Note that the string really is modified, no copy is made |
upcase-table | Variable |
A translate-string compatible translation map to convert
lowercase characters to uppercase characters.
|
downcase-table | Variable |
A map to convert uppercase characters to lowercase. |
flatten-table | Variable |
A translation map to convert newline characters to spaces. |
(translate-string "Foo" upcase-table) => "FOO" (translate-string "Foo" downcase-table) => "foo"
complete-string template list #!optional ignore-case | Function |
Return a string whose beginning matches the string template, and
is unique in the set of all strings in list which also match
template. If ignore-case is true, all matching
ignores case of characters.
(complete-string "foo" '("bar" "foobar" "forbarf" "foobat")) => "fooba" |
string-head-eq string-1 string-2 | Function |
Returns t if string-2 matches the beginning of string-1.
(string-head-eq "foobar" "foo") => t (string-head-eq "foo" "foobar") => () |
string-upper-case-p string | Function |
Return true if string contains no lower case characters. |
string-lower-case-p string | Function |
Return true if string contains no upper case characters. |
string-capitalized-p string | Function |
Return true if the first character of string is upper case. |
string-upcase string | Function |
Return a new string, an upper case copy of string. |
string-downcase string | Function |
Return a new string, a lower case copy of string. |
capitalize-string string | Function |
Return a new string, a copy of string with the first character in upper case. |
mapconcat function sequence separator | Function |
Call function for each member of sequence, concatenating the results. Between each pair of results, insert separator. Return the resulting string. |
sleep-for seconds #!optional milliseconds | Function |
Pause for a seconds (plus the optional milliseconds component) long period of time. Input becoming available will not break the sleep (see Process I/O). |
Use this function to attract the user's attention.
beep | Function |
Ring a bell somewhere. |
The message
function will show the user a small message
(typically no more than a single column of text). In graphical
applications it won't bring up a separate window, only
displaying the text in a status bar or something similar. In a
console-based environment, the message will be printed to the
stderr
stream, followed by a line break.
message #!optional display-now | Function |
Displays a one-line message, the string message. If display-now, every effort will be made to display the message as soon as possible, possibly before the next scheduled screen update (if applicable). |
As noted earlier any unused command line arguments are made available
to scripts through the command-line-args
variable
(see Invocation).
command-line-args | Variable |
The list of unused command line arguments, in their original order. |
The get-command-line-option
function may be used to scan this
list of arguments.
get-command-line-option option #!optional requires-arg | Function |
Returns t if option was specified on the command line
(option is typically a phrase beginning with -- ).
If requires-arg is true, the option requires a parameter, the value of which is returned. If a parameter isn't supplied an error is signalled. |
(setq command-line-args '("--foo" "bar")) => ("--foo" "bar") (get-command-line-option "--foo" t) => "bar" command-line-args => () (setq command-line-args '("--foo=bar")) => ("--foo=bar") (get-command-line-option "--foo" t) => "bar" command-line-args => ()
The subprocess handling of librep
provides a comprehensive
interface to starting and controlling external processes
(see Processes). However it can be overkill when all that is
required is to invoke a shell command, with its I/O going to the same
places as the interpreter's.
system command | Function |
Execute the shell command command synchronously, returning its
exit status. An error will be signalled if the shell process could not
be started.
The The subprocesses environment is copied from the current value of the
|
Note that the exit status is not the same as the return code of the command. It depends on the operating system, but under UNIX the return code can be found through right-shifting the exit status by eight bits. Low non-zero values represent that the process was killed by a signal.
It is possible to interrupt a running shell process in the same way as with a normal synchronous process (see Synchronous Processes). Interrupt the interpreter, it will send progressively harder-to-ignore signals to the child each interrupt, until it is eventually terminated.
The rep.io.timers
module (see Modules) allows a Lisp program
to create multiple asynchronous timers, each of which is primed to call
a specified function after a specified period of time. These functions
only work when the Lisp event loop is being used (i.e. at least one
recursive-edit
is currently in progress).
make-timer function #!optional seconds milliseconds | Function |
Create and return a new timer object. It will be set to call the Lisp
function function after seconds seconds plus
milliseconds milliseconds. function will be called with a
single argument, the timer object that has just fired.
If both seconds and milliseconds are undefined, or zero, the timer will be created but won't call function. After the time interval has passed, and function has been called,
the timer will not be restarted. Use the |
delete-timer timer | Function |
Prevent the timer object timer from calling the Lisp function
associated with it. Use the set-timer function to reset it.
|
set-timer timer #!optional seconds milliseconds | Function |
Reset the timer object timer. If either/both of seconds and milliseconds are defined the interval of the timer will be set to the specified time period. If neither are defined then the current interval of the timer is preserved. |
When you have written a Lisp program you will have to debug it (unless all your programs work first time?). There are two main classes of errors; syntax errors and semantic errors.
Syntax errors occur when the text you've typed out to represent your program is not a valid representation of a Lisp object (since a program is simply an ordered set of Lisp objects). When you try to load your program the Lisp reader will find the syntax error and tell you about, unfortunately though it probably won't be able to tell you exactly where the error is.
The most common source of syntax errors is too few or too many parentheses; the Jade or Emacs Ctrl-Meta-f and Ctrl-Meta-b commands can be used to show the structure of the program as the Lisp reader sees it.
Semantic errors are what we normally call bugs--errors in logic, the program is syntactically correct but doesn't do what you want it to. For these types of errors librep provides hooks to allow interactive debugging. The debugger supplied with librep uses these hooks to implement a simple command line debugger; programs using librep as an extension language may provide their own debugger interface.
There are several ways to enter the Lisp debugger; functions can be marked so that they cause the debugger to be entered when they are called, breakpoints can be written in functions or it can be called explicitly with a form to step through.
trace symbol | Command |
This command marks the symbol symbol so that each time its value
is dereferenced the debugger is entered when the next form is
evaluated. This can be used to set breakpoints on functions (or
variables).
When called interactively symbol is prompted for. |
untrace symbol | Command |
The opposite of trace --unmarks the symbol.
|
break | Function |
This function causes the debugger to be entered immediately. By putting
the form (break) at suitable points in your program simple
breakpoints can be created.
|
step form | Command |
This function invokes the debugger to step through the form form.
When called interactively form is prompted for. |
backtrace #!optional stream | Function |
Prints a description of the current Lisp function call stack to
stream (or standard-output if stream is undefined).
(backtrace (current-buffer)) -| #<subr backtrace> ((current-buffer)) nil -| #<closure eval-and-print> ((backtrace (current-buffer))) t => t Each line represents a stack frame, the first item is the called function, the second is the list of arguments applied to it. The third item is true if the list of arguments as displayed has already been evaluated. |
Whenever the Lisp debugger is entered the form waiting to be evaluated is printed, preceded by the current depth of execution in angular brackets. At this point the special debugger commands available are,
step
s
next
n
continue
c
return form
r form
print form
p form
form
f
backtrace
b
Entering a null string repeats the previous next
, step
,
or continue
command.
After the form has been evaluated (i.e. after you've typed one of the
commands above) the value of the form is printed in the buffer,
prefixed by the string =>
.
Note that it is also possible to make certain types of errors invoke the debugger immediately they are signalled, see Errors. Also note that the debugger is unable to step through compiled Lisp code.
This section of the manual gives advice about programming in
librep
.
For advice on getting the most out of the compiler, see Compilation Tips.
As already described, single-line comments in Lisp are introduced by a
semi-colon (;
) character. By convention a different number of
semi-colons is used to introduce different types of comments,
;
For example,
(defconst op-call #x08) ;call (stk[n] stk[n-1] ... stk[0]) ; pops n values, replacing the ; function with the result. (defconst op-push #x10) ;pushes constant # n
;;
For example,
(let ((fname (concat file-name ?c))) ;; Be sure to remove any partially written dst-file. (when (file-exists-p fname) (delete-file fname)))
Comments of this type are also placed before a function definition to describe the function. This saves wasting memory with a documentation string in a module's internal functions.
For example,
;; Compile a form which occurred at the `top-level' into a ;; byte code form. ;; defuns, defmacros, defvars, etc... are treated specially. ;; require forms are evaluated before being output uncompiled; ;; this is so any macros are brought in before they're used. (defun comp-compile-top-form (form) ...
;;;
For example,
;;; Notes: ;;; Instruction Encoding ;;; ==================== ;;; Instructions which get an argument (with opcodes of zero up to ...
;;;;
For example,
;;;; compiler.jl -- Simple compiler for Lisp files/forms
If you adhere to these standards the indentation functions provide by the Lisp mode will indent your comments to the correct depth.
This chapter will document the internals of librep
, including
how to embed the interpreter into general applications, and how to
write dynamically-loadable C libraries. Unfortunately most of it hasn't
been written. As always, the best reference is the source, Luke!
If the librep
interpreter crashes it's probably a bug (unless
you're using the rep-gtk
binding, in which case creating invalid
GTK widget hierarchies can easily crash the Lisp system). If the
interpreter hangs such that sending it interrupt signals doesn't fix
the problem, that's probably also a bug.
To help me fix any bugs found please try to collect as much meaningful information as possible. This will hopefully include stack backtraces (of both the C and Lisp stacks if possible), what features are loaded, what you did immediately before triggering the bug, a description of your the system, etc...
Please send any bug reports to the mailing list: librep-list@lists.sourceforge.net. Alternatively, the author may be contacted at: jsh@users.sourceforge.net.
*
: Arithmetic Functions
+
: Arithmetic Functions
-
: Arithmetic Functions
/
: Arithmetic Functions
/=
: Comparison Predicates
1+
: Arithmetic Functions
1-
: Arithmetic Functions
<
: Comparison Predicates
<=
: Comparison Predicates
=
: Comparison Predicates
>
: Comparison Predicates
>=
: Comparison Predicates
_
: i18n
abs
: Real Number Functions
accept-process-output
: Process I/O
acos
: Mathematical Functions
active-processes
: Process Objects
add-hook
: Normal Hooks
all-threads
: Creating Threads
alpha-char-p
: Characters
alphanumericp
: Characters
and
: Conditional Structures
append
: Building Lists
apply
: Calling Functions
apropos
: Obarrays
aref
: Array Functions
arrayp
: Array Functions
aset
: Array Functions
asin
: Mathematical Functions
assoc
: Association Lists
assq
: Association Lists
atan
: Mathematical Functions
atom
: Cons Cells
autoload
: Autoloading
backquote
: Backquoting
backtrace
: Debugging
beep
: Beeping
bindtextdomain
: i18n
boundp
: Void Variables
break
: Debugging
bytecodep
: Compilation Functions
call-hook
: Normal Hooks
call-process
: Synchronous Processes
call-with-current-continuation
: Continuations
call-with-dynamic-root
: Thread Contexts
call/cc
: Continuations
canonical-file-name
: File Names
capitalize-string
: String Functions
car
: Cons Cells
case
: Conditional Structures
catch
: Catch and Throw
cdr
: Cons Cells
ceiling
: Real Number Functions
char-downcase
: Characters
char-upcase
: Characters
close-file
: Destroying File Objects
closure-function
: Anonymous Functions
closurep
: Anonymous Functions
compile-directory
: Compilation Functions
compile-file
: Compilation Functions
compile-form
: Compilation Functions
compile-function
: Compilation Functions
compile-module
: Compilation Functions
complete-string
: String Functions
concat
: Strings
cond
: Conditional Structures
condition-case
: Errors
cons
: Cons Cells
consp
: Cons Cells
continue-process
: Process States
copy-file
: Manipulating Files
copy-file-from-local-fs
: File Handlers
copy-file-to-local-fs
: File Handlers
copy-sequence
: Sequence Functions
copy-stream
: Output Functions
cos
: Mathematical Functions
current-thread
: Creating Threads
current-time
: Timestamps
current-time-string
: Formatting Dates
datum-ref
: Datums
datum-set
: Datums
declare
: Compiler Declarations
defconst
: Defining Variables
define
: Definitions
define-datum-printer
: Datums
define-interface
: Module Interfaces
define-record-discloser
: Records
define-record-type
: Records
define-structure
: Module Definition
define-structures
: Module Definition
defmacro
: Defining Macros
defun
: Defining Functions
defvar
: Defining Variables
delete
: Modifying Lists
delete-directory
: Manipulating Directories
delete-file
: Manipulating Files
delete-from-queue
: Queues
delete-if
: Mapping Functions
delete-if-not
: Mapping Functions
delete-timer
: Timers
delq
: Modifying Lists
denominator
: Rational Functions
dequeue
: Queues
digit-char-p
: Characters
directory-file-name
: File Names
directory-files
: Manipulating Directories
disassemble-fun
: Disassembly
do
: Looping Structures
elt
: Sequence Functions
enqueue
: Queues
eq
: Equality Predicates
eq-hash
: Hash Tables
eql
: Equality Predicates
equal
: Equality Predicates
equal-hash
: Hash Tables
eval
: Evaluation
eval-after-load
: Load Function
eval-when-compile
: Compiler Declarations
evenp
: Numeric Predicates
exact->inexact
: Rational Functions
exactp
: Numeric Predicates
exp
: Mathematical Functions
expand-file-name
: File Names
expand-last-match
: Regexp Functions
expt
: Mathematical Functions
featurep
: Features
file-binding
: Functions on File Objects
file-bound-stream
: Functions on File Objects
file-directory-p
: File Information
file-exists-p
: File Information
file-handler-data
: Functions on File Objects
file-modes
: File Information
file-modes-as-string
: File Information
file-modtime
: File Information
file-name-absolute-p
: File Names
file-name-as-directory
: File Names
file-name-directory
: File Names
file-name-nondirectory
: File Names
file-newer-than-file-p
: File Information
file-nlinks
: File Information
file-owner-p
: File Information
file-readable-p
: File Information
file-regular-p
: File Information
file-size
: File Information
file-symlink-p
: File Information
file-writable-p
: File Information
filep
: File Objects
filter
: Mapping Functions
find-symbol
: Obarrays
fix-time
: Timestamps
floor
: Real Number Functions
fluid
: Fluid Variables
fluid-set
: Fluid Variables
flush-file
: Functions on File Objects
format
: Formatted Output
funcall
: Calling Functions
functionp
: Functions
garbage-collect
: Garbage Collection
gcd
: Integer Functions
gensym
: Creating Symbols
get
: Property Lists
get-command-line-option
: Command Line Options
get-output-stream-string
: Output Streams
getenv
: Environment Variables
has-type-p
: Datums
if
: Conditional Structures
inexact->exact
: Real Number Functions
inexactp
: Numeric Predicates
input-stream-p
: Streams
integerp
: Numeric Predicates
intern
: Interning
intern-symbol
: Interning
interrupt-process
: Signalling Processes
keywordp
: Keyword Symbols
kill-process
: Signalling Processes
last
: Accessing List Elements
lcm
: Integer Functions
length
: Sequence Functions
let
: Looping Structures, Local Variables
let*
: Local Variables
let-fluids
: Fluid Variables
letrec
: Local Variables
list
: Building Lists
list*
: Building Lists
listp
: Lists
load
: Load Function
local-file-name
: File Names
log
: Mathematical Functions
logand
: Bitwise Functions
logior
: Bitwise Functions
lognot
: Bitwise Functions
logxor
: Bitwise Functions
lower-case-p
: Characters
lsh
: Bitwise Functions
macroexpand
: Macro Expansion
macrop
: Macros
make-closure
: Anonymous Functions
make-datum
: Datums
make-directory
: Manipulating Directories
make-file-from-stream
: File Handlers
make-fluid
: Fluid Variables
make-guardian
: Guardians
make-keyword
: Keyword Symbols
make-list
: Building Lists
make-mutex
: Mutexes
make-obarray
: Obarrays
make-process
: Process Objects
make-queue
: Queues
make-string
: Strings
make-string-input-stream
: Input Streams
make-string-output-stream
: Output Streams
make-symbol
: Creating Symbols
make-symlink
: Manipulating Symlinks
make-table
: Hash Tables
make-temp-name
: File Names
make-thread
: Creating Threads
make-timer
: Timers
make-vector
: Vectors
make-weak-table
: Hash Tables
makunbound
: Void Variables
mapc
: Mapping Functions
mapcar
: Mapping Functions
mapconcat
: String Functions
match-end
: Regexp Functions
match-start
: Regexp Functions
max
: Comparison Predicates
maybe-obtain-mutex
: Mutexes
member
: Accessing List Elements
memq
: Accessing List Elements
message
: Messages
min
: Comparison Predicates
mod
: Integer Functions
modulo
: Integer Functions
mutexp
: Mutexes
nconc
: Modifying Lists
negativep
: Numeric Predicates
not
: Conditional Structures
nreverse
: Modifying Lists
nth
: Accessing List Elements
nthcdr
: Accessing List Elements
null
: Lists
numberp
: Numbers
numerator
: Rational Functions
obtain-mutex
: Mutexes
oddp
: Numeric Predicates
open-file
: Creating File Objects
or
: Conditional Structures
output-stream-p
: Streams
parse-date
: Parsing Dates
positivep
: Numeric Predicates
prin1
: Output Functions
prin1-to-string
: Output Functions
princ
: Output Functions
print
: Output Functions
process-args
: Process Objects
process-connection-type
: Asynchronous Processes
process-dir
: Process Objects
process-error-stream
: Process I/O
process-exit-status
: Process Information
process-exit-value
: Process Information
process-function
: Process States
process-id
: Process Information
process-in-use-p
: Process States
process-output-stream
: Process I/O
process-prog
: Process Objects
process-running-p
: Process States
process-stopped-p
: Process States
processp
: Process Objects
prog1
: Sequencing Structures
prog2
: Sequencing Structures
progn
: Sequencing Structures
provide
: Features
put
: Property Lists
queue->list
: Queues
queue-empty-p
: Queues
queue-length
: Queues
queuep
: Queues
quote
: Quoting
quote-regexp
: Regexp Functions
quotient
: Integer Functions
random
: Random Numbers
rassoc
: Association Lists
rassq
: Association Lists
rationalp
: Numeric Predicates
read
: Input Functions, The Lisp Reader
read-char
: Input Functions
read-from-string
: Input Functions
read-line
: Input Functions
read-symlink
: Manipulating Symlinks
realp
: Numeric Predicates
release-mutex
: Mutexes
remainder
: Integer Functions
remote-ftp-add-passwd
: Remote Files
remove
: Building Lists
remove-hook
: Normal Hooks
remq
: Building Lists
rename-file
: Manipulating Files
require
: Features
reverse
: Building Lists
round
: Real Number Functions
rplaca
: Cons Cells
rplacd
: Cons Cells
run-byte-code
: Compilation Functions
seek-file
: Functions on File Objects
sequencep
: Sequences, Sequence Functions
set
: Setting Variables
set-file-handler-data
: Functions on File Objects
set-file-modes
: File Information
set-input-handler
: Functions on File Objects
set-process-args
: Process Objects
set-process-connection-type
: Asynchronous Processes
set-process-dir
: Process Objects
set-process-error-stream
: Process I/O
set-process-function
: Process States
set-process-output-stream
: Process I/O
set-process-prog
: Process Objects
set-timer
: Timers
setenv
: Environment Variables
setplist
: Property Lists
setq
: Setting Variables
signal
: Errors
signal-process
: Signalling Processes
sin
: Mathematical Functions
sit-for
: Process I/O
sleep-for
: Sleeping
sort
: Modifying Lists
space-char-p
: Characters
special-form-p
: Special Forms
sqrt
: Mathematical Functions
start-process
: Asynchronous Processes
stderr-file
: Creating File Objects
stdin-file
: Creating File Objects
stdout-file
: Creating File Objects
step
: Debugging
stop-process
: Process States
streamp
: Streams
string-capitalized-p
: String Functions
string-downcase
: String Functions
string-equal
: Strings
string-hash
: Hash Tables
string-head-eq
: String Functions
string-lessp
: Strings
string-looking-at
: Regexp Functions
string-lower-case-p
: String Functions
string-match
: Regexp Functions
string-upcase
: String Functions
string-upper-case-p
: String Functions
string<
: Strings
string=
: Strings
stringp
: Strings
structure
: Module Definition
subr-name
: Functions
subrp
: Functions
substring
: Strings
symbol-hash
: Hash Tables
symbol-name
: Symbol Attributes
symbol-plist
: Property Lists
symbol-value
: Variables
symbolp
: Symbols
system
: Shell Commands
system-name
: System Information
table-bound-p
: Hash Tables
table-ref
: Hash Tables
table-set
: Hash Tables
table-unset
: Hash Tables
table-walk
: Hash Tables
tablep
: Hash Tables
tan
: Mathematical Functions
textdomain
: i18n
thread-delete
: Deleting Threads
thread-deleted-p
: Deleting Threads
thread-forbid
: Manipulating Threads
thread-join
: Manipulating Threads
thread-permit
: Manipulating Threads
thread-suspend
: Manipulating Threads
thread-suspended-p
: Manipulating Threads
thread-wake
: Manipulating Threads
thread-yield
: Manipulating Threads
threadp
: Creating Threads
throw
: Catch and Throw
time-later-p
: Timestamps
trace
: Debugging
translate-string
: String Functions
truncate
: Real Number Functions
unintern
: Interning
unless
: Conditional Structures
unsetenv
: Environment Variables
untrace
: Debugging
unwind-protect
: Cleanup Forms
upper-case-p
: Characters
useless-function
: Descriptions
user-full-name
: User Information
user-home-directory
: User Information
user-login-name
: User Information
vector
: Vectors
vectorp
: Vectors
when
: Conditional Structures
while
: Looping Structures
with-fluids
: Fluid Variables
with-internal-definitions
: Definitions
without-interrupts
: Manipulating Threads
write
: Output Functions
zerop
: Numeric Predicates
after-gc-hook
: Garbage Collection
after-load-alist
: Load Function
backtrace-on-error
: Errors
command-line-args
: Command Line Options, Invocation
date-vec-day
: Parsing Dates
date-vec-day-abbrev
: Parsing Dates
date-vec-epoch-time
: Parsing Dates
date-vec-hour
: Parsing Dates
date-vec-minute
: Parsing Dates
date-vec-month
: Parsing Dates
date-vec-month-abbrev
: Parsing Dates
date-vec-second
: Parsing Dates
date-vec-timezone
: Parsing Dates
date-vec-year
: Parsing Dates
debug-on-error
: Errors
default-directory
: File Names
dl-load-path
: Load Function
downcase-table
: String Functions
features
: Features
file-handler-alist
: File Handlers
flatten-table
: String Functions
format-hooks-alist
: Formatted Output
garbage-threshold
: Garbage Collection
grains-of-sand
: Descriptions
idle-garbage-threshold
: Garbage Collection
lisp-lib-directory
: Load Function
load-filename
: Load Function
load-path
: Load Function
max-lisp-depth
: Evaluation
obarray
: Obarrays
operating-system
: System Information
print-escape
: Output Functions
print-length
: Output Functions
print-level
: Output Functions
process-environment
: Process Objects
remote-auto-backend-alist
: Remote Files
remote-default-backend
: Remote Files
remote-default-user
: Remote Files
remote-ftp-anon-passwd
: Remote Files
remote-ftp-anon-users
: Remote Files
remote-ftp-display-progress
: Remote Files
remote-ftp-show-messages
: Remote Files
remote-host-user-alist
: Remote Files
rep-build-id
: System Information
rep-version
: System Information
standard-error
: Output Streams
standard-input
: Input Streams
standard-output
: Output Streams
upcase-table
: String Functions
rep
scripts: Invocation
rep
scripts: Invocation
In this case the list (+ 1 2)
(i.e. the list
containing three elements, the symbol +
and, the numbers 1 and
2), represents a function application. The first element in the list is
the name of the function to be called, all other elements are the
arguments to apply to it. Since the +
function adds a series of
numbers, the above function call is actually performing the computation
1 + 2
.
However, depending on implementation restrictions, very large integers may be coerced to an inexact representation.
Only used when librep
is embedded within another
application.
The default form is evaluated in the environment of the closure being called, but without any of the bindings created by the lambda expression.
In this example, there is no need to pass
the value of x
into bar
, since the binding of x
is
already within the scope of bar
.
The usual convention is to prefix the variable name with a unique string derived from the module name.
Guardians were first described in a paper by R. Kent Dybvig, Carl Bruggeman, and David Eby: "Guardians in a Generation-Based Garbage Collector", ACM SIGPLAN Conference on Programming Language Design and Implementation, June 1993.