Perfection is attained
not when there is nothing left to add
but when there is nothing left to take away
(Antoine de Saint-Exupéry)
(c) Software Lab. Alexander Burger
This document describes the concepts, data types, and kernel functions of the Pico Lisp system.
This is not a Lisp tutorial. For an introduction to Lisp, a traditional Lisp book like "Lisp" by Winston/Horn (Addison-Wesley 1981) is recommended. Note, however, that there are significant differences between Pico Lisp and Maclisp (and even greater differences to Common Lisp).
Please take a look at the Pico Lisp Tutorial for an explanation of some aspects of Pico Lisp, and scan through the list of Frequently Asked Questions (FAQ).
Pico Lisp is the result of a language design study, trying to answer the question "What is a minimal but useful architecture for a virtual machine?". Because opinions differ about what is meant by "minimal" and "useful", there are many answers to that question, and people might consider other solutions more "minimal" or more "useful". But from a practical point of view, Pico Lisp proved to be a valuable answer to that question.
First of all, Pico Lisp is a virtual machine architecture, and then a programming language. It was designed in a "bottom up" way, and "bottom up" is also the most natural way to understand and to use it: Form Follows Function.
Pico Lisp was used in several commercial and research programming projects since 1988. Its internal structures are simple enough, allowing an experienced programmer always to fully understand what's going on under the hood, and its language features, efficiency and extensibility make it suitable for almost any practical programming task.
In a nutshell, emphasis was put on four design objectives. The Pico Lisp system should be
An important point in the Pico Lisp philosophy is the knowledge about the architecture and data structures of the internal machinery. The high-level constructs of the programming language directly map to that machinery, making the whole system both understandable and predictable.
This is similar to assembly language programming, where the programmer has complete control over the machine.
The Pico Lisp virtual machine is both simpler and more powerful than most current (hardware) processors. At the lowest level, it is constructed from a single data structure called "cell":
+-----+-----+
| CAR | CDR |
+-----+-----+
A cell is a pair of machine words, which traditionally are called
CAR
and CDR
in the Lisp terminology. These words can
represent either a numeric value (scalar) or the address of another cell
(pointer). All higher level data structures are built out of cells.
The type information of higher level data is contained in the pointers to these data. Assuming the implementation on a byte-addressed physical machine, and a pointer size of typically 4 bytes, each cell has a size of 8 bytes. Therefore, the pointer to a cell must point to an 8-byte boundary, and its bit-representation will look like:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx000
(the 'x'
means "don't care"). For the individual data types, the
pointer is adjusted to point to other parts of a cell, in effect setting some of
the lower three bits to non-zero values. These bits are then used by the
interpreter to determine the data type.
In any case, bit(0) - the least significant of these bits - is reserved as a mark bit for garbage collection.
Initially, all cells in the memory are unused (free), and linked together to form a "free list". To create higher level data types at runtime, cells are taken from that free list, and returned by the garbage collector when they are no longer needed. All memory management is done via that free list; there are no additional buffers, string spaces or special memory areas (With two exceptions: A certain fixed area of memory is set aside to contain the executable code and global variables of the interpreter itself, and a standard push down stack for return addresses and temporary storage. Both are not directly accessible by the programmer).
On the virtual machine level, Pico Lisp supports
NIL
.
They are all built from the single cell data structure, and all runtime data cannot consist of any other types than these three.
The following diagram shows the complete data type hierarchy, consisting of the three base types and the symbol variations:
cell
|
+--------+--------+
| | |
Number Symbol List
|
|
+--------+--------+--------+
| | | |
NIL Internal Transient External
A number can represent a signed integral value of arbitrary size. The
CAR
s of one or more cells hold the number's "digits" (each in the
machine's word size), to store the number's binary representation.
Number
|
V
+-----+-----+ +-----+-----+ +-----+-----+
|'DIG'| ---+---> |'DIG'| ---+---> |'DIG'| / |
+-----+-----+ +-----+-----+ +-----+-----+
The first cell holds the least significant digit. The least significant bit of that digit represents the sign.
The pointer to a number points into the middle of the CAR
, with
an offset of 2 from the cell's start address. Therefore, the bit pattern of a
number will be:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx010
Thus, a number is recognized by the interpreter when bit(1) is non-zero.
A symbol is more complex than a number. Each symbol has a value, and
optionally a name and an arbitrary number of properties. The CAR
of
a symbol cell is also called VAL
, and the CDR
points
to the symbol's tail. As a minimum, a symbol consists of a single cell, and has
no name or properties:
Symbol
|
V
+-----+-----+
| VAL | / |
+-----+-----+
That is, the symbol's tail is empty (points to NIL
, as indicated
by the '/' character).
The pointer to a symbol points to the CDR
of the cell, with an
offset of 4 from the cell's start address. Therefore, the bit pattern of a
symbol will be:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx100
Thus, a symbol is recognized by the interpreter when bit(2) is non-zero. In addition, it is possible that bit(1) is also set for a symbol (This is the case for external symbols).
A property is a key-value-pair, represented as a cell in the symbol's tail.
This is called a "property list". The property list may be terminated by a
number representing the symbol's name. In the following example, a symbol with
the name "abc"
has three properties:
Symbol
|
V
+-----+-----+
| VAL | ---+---+
+-----+-----+ | tail
|
+------------+
|
V name
+-----+-----+ +-----+-----+ +-----+-----+ +-----+-----+
| | | ---+---> | KEY | ---+---> | | | ---+---> |'cba'| / |
+--+--+-----+ +-----+-----+ +--+--+-----+ +-----+-----+
| |
V V
+-----+-----+ +-----+-----+
| VAL | KEY | | VAL | KEY |
+-----+-----+ +-----+-----+
Each property in a symbol's tail is either a symbol (then it represents a
boolean value), or a cell with the property key in its CDR
and the
property value in its CAR
. In both cases, the key should be a
symbol, because searches in the property list are performed using pointer
comparisons.
The name of a symbol is stored as a number at the end of the tail. It contains the characters of the name in UTF-8 encoding, using between one and three 8-bit-bytes per character. The first byte of the first character is stored in the lowest 8 bits of the number.
All symbols have the above structure, but depending on scope and
accessibility there are actually four types of symbols: NIL
, internal, transient and external symbols.
NIL
is a special symbol which exists exactly once in the whole
system. It is used
For that, NIL
has a special structure:
NIL: /
|
V
+-----+-----+-----+-----+
| / | / | / | / |
+-----+--+--+-----+-----+
The reason for that structure is NIL
's dual nature both as a
symbol and as a list:
NIL
for its VAL
, and
be without properties
NIL
should give NIL
both for
its CAR
and for its CDR
These requirements are fulfilled by the above structure.
Internal Symbols are all those "normal" symbols, as they are used for function definitions and variable names. They are "interned" into a hashed list structure, so that it is possible to find an internal symbol by searching for its name.
There cannot be two different internal symbols with the same name.
Initially, a new internal symbol's VAL
is NIL
.
Transient symbols are only interned into a hashed list structure for a certain time (e.g. while reading the current source file), and are released after that. That means, a transient symbol cannot be accessed then by its name, and there may be several transient symbols in the system having the same name.
Transient symbols are used
static
identifiers in the C
language family)
Initially, a new transient symbol's VAL
is that symbol itself.
A transient symbol without a name can be created with the box
or new
functions.
External symbols reside in a database file, and are loaded into memory - and written back to the file - dynamically as needed, and transparent to the programmer.
The interpreter recognizes external symbols, because in addition to the symbol bit(2), also bit(1) is set:
xxxxxxxxxxxxxxxxxxxxxxxxxxxxx110
There cannot be two different external symbols with the same name. External symbols are maintained in hash structures while they are loaded into memory, and have their external location (disk block, network URL, etc.) directly coded into their names.
Initially, a new external symbol's VAL
is NIL
,
unless otherwise specified at creation time.
A list is a sequence of one or more cells, holding numbers, symbols, or lists. Lists are used in Pico Lisp to emulate composite data structures like arrays, trees, stacks or queues.
In contrast to lists, numbers and symbols are collectively called "Atoms".
Typically, the CDR
of each cell in a list points to the
following cell, except for the last cell which points NIL
. If,
however, the CDR
of the last cell points to an atom, that cell is
called a "dotted pair" (because of its I/O syntax with a dot '.' between the two
values).
The Pico Lisp interpreter has complete knowledge of all data in the system, due to the type information associated with every pointer. Therefore, an efficient garbage collector mechanism can easily be implemented. Pico Lisp employs a simple but fast mark-and-sweep garbage collector.
As the collection process is very fast (in the order of milliseconds per megabyte), it was not necessary to develop more complicated, time-consuming and error-prone garbage collection algorithms (e.g. incremental collection). A compacting garbage collector is also not necessary, because the single cell data type cannot cause heap fragmentation.
Lisp was chosen as the programming language, because of its clear and simple structure.
In some previous versions, a Forth-like syntax was also implemented on top of a similar virtual machine (Lifo). Though that language was more flexible and expressive, the traditional Lisp syntax proved easier to handle, and the virtual machine can be kept considerably simpler. Pico Lisp inherits the major advantages of classical Lisp systems like
In the following, some concepts and peculiarities of the Pico Lisp language and environment are described.
When Pico Lisp is invoked from the command line, an arbitrary number of arguments may follow the command name.
By default, each argument is the name of a file to be executed by the
interpreter. If, however, the argument's first character is a hyphen '-', then
the rest of that argument is taken as a function call (without the surrounding
parentheses). A hyphen by itself as an argument stops evaluation of the rest of
the command line (it may be processed later using the argv
function). This mechanism corresponds to calling
(load T)
.
As a convention, Pico Lisp source files have the extension ".l
".
Note that the Pico Lisp executable itself does not expect or accept any command line flags or options. They are reserved for application programs.
The simplest and shortest invocation of Pico Lisp does nothing, and exits
immediately by calling bye
:
$ bin/picolisp -bye
$
In interactive mode, the Pico Lisp interpreter (see load
) will also exit when an empty line is entered:
$ bin/picolisp
: # Typed RETURN
$
To start up the standard Pico Lisp environment, several files should be loaded. The most commonly used things are in "lib.l" and in a bunch of other files, which are in turn loaded by "ext.l". Thus, a typical call would be:
$ bin/picolisp lib.l ext.l
The recommended way, however, is to call the "p" shell script, which includes
"lib.l" and "ext.l". Given that your current project is loaded by some file
"myProject.l" and your startup function is main
, your invocation
would look like:
$ ./p myProject.l -main
For interactive development and debugging it is recommended also to load "dbg.l", to get the vi-style command line editor, single-stepping, tracing and other debugging utilities.
$ ./p dbg.l myProject.l -main
In any case, the directory part of the first file name supplied on the
command line is remembered internally as the Pico Lisp Home Directory.
This path is later automatically substituted for any leading "@
"
character in file name arguments to I/O functions (see path
).
In Lisp, each internal data structure has a well-defined external representation in human-readable format. All kinds of data can be written to a file, and restored later to their original form by reading that file.
In normal operation, the Pico Lisp interpreter continuously executes an infinite "read-eval-print loop". It reads one expression at a time, evaluates it, and prints the result to the console. Any input into the system, like data structures and function definitions, is done in a consistent way no matter whether it is entered at the console or read from a file.
Comments can be embedded in the input stream with the hash #
character. Everything up to the end of that line will be ignored by the reader.
: (* 1 2 3) # This is a comment
-> 6
Here is the I/O syntax for the individual Pico Lisp data types:
A number consists of an arbitrary number of digits ('0'
through
'9'
), optionally preceded by a sign character ('+'
or
'-'
). Legal number input is:
: 7
-> 7
: -12345678901245678901234567890
-> -12345678901245678901234567890
Fixed-point numbers can be input by embedding a decimal point
'.'
, and setting the global variable *Scl
appropriately:
: *Scl
-> 0
: 123.45
-> 123
: 456.78
-> 457
: (setq *Scl 3)
-> 3
: 123.45
-> 123450
: 456.78
-> 456780
Thus, fixed-point input simply scales the number to an integer value
corresponding to the number of digits in *Scl
.
Formatted output of scaled fixed-point values can be done with the format
function:
: (format 1234567890 2)
-> "12345678.90"
: (format 1234567890 2 "." ",")
-> "12,345,678.90"
The reader is able to recognize the individual symbol types from their syntactic form. A symbol name should - of course - not look like a legal number (see above).
In general, symbol names are case-sensitive. car
is not the same
as CAR
.
Besides for standard normal form, NIL
is also recognized as
()
, []
or ""
.
: NIL
-> NIL
: ()
-> NIL
: ""
-> NIL
Output will always appear as NIL
.
Internal symbol names can consist of any printable (non-whitespace) character, except for the following meta characters:
" ' ( ) [ ] ` ~
As a rule, anything not recognized by the reader as another data type will be returned as an internal symbol.
A transient symbol is anything surrounded by double quotes '"
'.
With that, it looks - and can be used - like a string constant in other
languages. However, it is a real symbol, and may be assigned a value or a
function definition, and properties.
Initially, a transient symbol's value is that symbol itself, so that it does not need to be quoted for evaluation:
: "This is a string"
-> "This is a string"
However, care must be taken when assigning a value to a transient symbol. This may cause unexpected behavior:
: (setq "This is a string" 12345)
-> 12345
: "This is a string"
-> 12345
The name of a transient symbol can contain any character. A double quote
character can be escaped with a backslash '\
', and a backslash
itself has to be escaped with another backslash. Control characters can be
written with a preceding hat '^
' character.
: "We^Ird\\Str\"ing"
-> "We^Ird\\Str\"ing"
: (chop @)
-> ("W" "e" "^I" "r" "d" "\\" "S" "t" "r" "\"" "i" "n" "g")
The hash table for transient symbols is cleared automatically before and
after load
ing a source file, or it can be reset
explicitly with the ====
function. With that
mechanism, it is possible to create symbols with a local access scope, not
accessible from other parts of the program.
A special case of transient symbols are anonymous symbols. These are
symbols without name (see box
, box?
or new
). They print
as a dollar sign ($
) followed by a decimal digit string (actually
their machine address).
External symbol names are surrounded by braces ('{'
and
'}'
). The characters of the symbol's name itself identify the
physical location of the external object. This is currently the number of the
starting block in the database file, encoded in base-64 notation (characters
'0
' through '9
', ':
' through
';
', 'A
' through 'Z
' and 'a
'
through 'z
'). Later versions might include other formats like
Internet URL's.
Lists are surrounded by parentheses ('('
and ')'
).
(A)
is a list consisting of a single cell, with the symbol
A
in its CAR
, and NIL
in its
CDR
.
(A B C)
is a list consisting of three cells, with the symbols
A
, B
and C
respectively in their
CAR
, and NIL
in the last cell's CDR
.
(A . B)
is a "dotted pair", a list consisting of a single cell,
with the symbol A
in its CAR
, and B
in
its CDR
.
Pico Lisp has built-in support for reading and printing simple circular
lists. If the dot in a dotted-pair notation is immediately followed by a closing
parenthesis, it indicates that the CDR
of the last cell points back
to the beginning of that list.
: (let L '(a b c) (conc L L))
-> (a b c .)
: (cdr '(a b c .))
-> (b c a .)
: (cddddr '(a b c .))
-> (b c a .)
A similar result can be achieved with the function circ
. Such lists must be used with care, because many
functions won't terminate or will crash when given such a list.
Read-macros in Pico Lisp are special forms that are recognized by the reader,
and modify its behavior. Note that they take effect immediately while reading an
expression, and are not seen by the eval
in the main loop.
The most prominent read-macro in Lisp is the single quote character
'
, which expands to a call of the quote
function. Note that the single quote character is
also printed instead of the full function name.
: '(a b c)
-> (a b c)
: '(quote . a)
-> 'a
: (cons 'quote 'a) # (quote . a)
-> 'a
: (list 'quote 'a) # (quote a)
-> '(a)
A comma (,
) will cause the reader to collect the following data
item into the global variable *Uni
, and to
return a previously inserted equal item if present. This makes it possible to
create a unique list of references to data which do normally not follow the
rules of pointer equality.
A single backquote character `
will cause the reader to evaluate
the following expression, and return the result.
: '(a `(+ 1 2 3) z)
-> (a 6 z)
A tilde character ~
inside a list will cause the reader to
evaluate the following expression, and splice the result into the list.
: '(a b c ~(list 'd 'e 'f) g h i)
-> (a b c d e f g h i)
Brackets ('['
and ']'
) can be used as super
parentheses. A closing bracket will match the innermost opening bracket, or all
currently open parentheses.
: '(a (b (c (d]
-> (a (b (c (d))))
: '(a (b [c (d]))
-> (a (b (c (d))))
Finally, reading the sequence '{}
' will result in a new
anonymous symbol with value NIL
, equivalent to a call to box
without arguments.
: '({} {} {})
-> ($134599965 $134599967 $134599969)
: (mapcar val @)
-> (NIL NIL NIL)
Pico Lisp tries to evaluate any expression encountered in the read-eval-print loop. Basically, it does so by applying the following three rules:
VAL
).
CAR
as the
function and the CDR
the arguments to that function. These
arguments are in turn evaluated according to these three rules.
: 1234
-> 1234 # Number evaluates to itself
: *Pid
-> 22972 # Symbol evaluates to its VAL
: (+ 1 2 3)
-> 6 # List is evaluated as a function call
For the third rule, however, things get a bit more involved. First - as a
special case - if the CAR
of the list is a number, the whole list
is returned as it is:
: (1 2 3 4 5 6)
-> (1 2 3 4 5 6)
This is not really a function call but just a convenience to avoid having to quote simple data lists.
Otherwise, if the CAR
is a symbol or a list, Pico Lisp tries to
obtain an executable function from that, by either using the symbol's value, or
by evaluating the list.
What is an executable function? Or, said in another way, what can be applied to a list of arguments, to result in a function call? A legal function in Pico Lisp is
quote
) or evaluate only some of their arguments (e.g.
setq
).
CAR
is either a symbol or a list of symbols, and whose
CDR
is a list of expressions. Note: In contrast to other Lisp
implementations, the symbol LAMBDA itself does not exist in Pico Lisp but is
implied from context.
A few examples should help to understand the practical consequences of these
rules. In the most common case, the CAR
will be a symbol defined as
a function, like the *
in:
: (* 1 2 3) # Call the function '*'
-> 6
Inspecting the VAL
of *
, however, gives
: * # Get the VAL of the symbol '*'
-> 67291944
The VAL
of *
is a number. In fact, it is the
numeric representation of a C
-function pointer, i.e. a pointer to
executable code. This is the case for all built-in functions of Pico Lisp.
Other functions in turn are written as Lisp expressions:
: (de foo (X Y) # Define the function 'foo'
(* (+ X Y) (+ X Y)) )
-> foo
: (foo 2 3) # Call the function 'foo'
-> 25
: foo # Get the VAL of the symbol 'foo'
-> ((X Y) (* (+ X Y) (+ X Y)))
The VAL
of foo
is a list. It is the list that was
assigned to foo
with the de
function. It would be
perfectly legal to use setq
instead of de
:
: (setq foo '((X Y) (* (+ X Y) (+ X Y))))
-> ((X Y) (* (+ X Y) (+ X Y)))
: (foo 2 3)
-> 25
If the VAL
of foo
were another symbol, that
symbol's VAL
would be used instead to search for an executable
function.
As we said above, if the CAR
of the evaluated expression is not
a symbol but a list, that list is evaluated to obtain an executable function.
: ((intern (pack "c" "a" "r")) (1 2 3))
-> 1
Here, the intern
function returns the symbol car
whose VAL
is used then. It is also legal, though quite dangerous,
to use the code-pointer directly:
: car
-> 67306152
: ((* 2 33653076) (1 2 3))
-> 1
When an executable function is defined in Lisp itself, we call it a lambda expression. A lambda expression always has a
list of executable expressions as its CDR
. The CAR
,
however, must be a either a list of symbols, or a single symbol, and it controls
the evaluation of the arguments to the executable function according to the
following rules:
CAR
is a list of symbols
VAL
's of the symbols are restored to their
original values. This is the most common case, a fixed number of arguments is
passed to the function.
CAR
is the symbol @
args
, next
, arg
and rest
functions. This allows to define functions with a
variable number of evaluated arguments.
CAR
is a single symbol In all cases, the return value is the result of the last expression in the body.
: (de foo (X Y Z) # CAR is a list of symbols
(list X Y Z) ) # Return a list of all arguments
-> foo
: (foo (+ 1 2) (+ 3 4) (+ 5 6))
-> (3 7 11) # all arguments are evaluated
: (de foo X # CAR is a single symbol
X ) # Return the argument
-> foo
: (foo (+ 1 2) (+ 3 4) (+ 5 6))
-> ((+ 1 2) (+ 3 4) (+ 5 6)) # the whole unevaluated list is returned
: (de foo @ # CAR is the symbol '@'
(list (next) (next) (next)) ) # Return the first three arguments
-> foo
: (foo (+ 1 2) (+ 3 4) (+ 5 6))
-> (3 7 11) # all arguments are evaluated
Note that these forms can also be combined. For example, to evaluate only the
first two arguments, bind the results to X
and Y
, and
bind all other arguments (unevaluated) to Z
:
: (de foo (X Y . Z) # CAR is a list with a dotted-pair tail
(list X Y Z) ) # Return a list of all arguments
-> foo
: (foo (+ 1 2) (+ 3 4) (+ 5 6))
-> (3 7 ((+ 5 6))) # two arguments are evaluated
Or, a single argument followed by a variable number of arguments:
: (de foo (X . @) # CAR is a dotted-pair with '@'
(println X) # print the first evaluated argument
(while (args) # while there are more arguments
(println (next)) ) ) # print the next one
-> foo
: (foo (+ 1 2) (+ 3 4) (+ 5 6))
3 # X
7 # Next arg
11
-> 11
During the evaluation of an expression, the Pico Lisp interpreter can be
interrupted at any time by hitting Ctrl-C
. It will then enter the
breakpoint routine, as if !
were called.
Hitting RETURN
at that point will continue evaluation, while
(quit)
will abort evaluation and return the
interpreter to the top level.
See also debug
, e
, ^
and *Dbg
When a runtime error occurs, execution is stopped and an error handler is entered.
The error handler resets the I/O channels to the console, and displays the
location (if possible) and the reason of the error, followed by an error
message. That message is also stored in the global *Msg
. If the VAL
of the global *Err
is non-NIL
it is executed as a
prg
body. If the standard input is from a terminal, a
read-eval-print loop (with a question mark "?
" as prompt) is
entered (the loop is exited when an empty line is input). Then all pending
finally
expressions are executed, all
variable bindings restored, and all files closed. If the standard input is not
from a terminal, the interpreter terminates. Otherwise it is reset to its
top-level state.
If the VAL
of the global *Rst
is non-NIL
, no interactive read-eval-print loop will be entered,
and that VAL
will be executed instead - after the above cleanup was
done - as a prg
body.
: (de foo (A B) (badFoo A B)) # 'foo' calls an undefined symbol
-> foo
: (foo 3 4) # Call 'foo'
!? (badFoo A B) # Error handler entered
badFoo -- Undefined
? A # Inspect 'A'
-> 3
? B # Inspect 'B'
-> 4
? # Empty line: Exit
:
In certain situations, the result of the last evaluation is stored in the
VAL
of the symbol @
. This can be very convenient,
because it often makes the assignment to temporary variables unnecessary.
load
@@@
,
@@
and @
, in that order (i.e the latest result is in
@
).
: (+ 1 2 3)
-> 6
: (/ 128 4)
-> 32
: (- @ @@) # Subtract the last two results
-> 26
@
.
: (while (read) (println 'got: @))
abc # User input
got: abc # print result
123 # User input
got: 123 # print result
NIL
-> 123
: (setq L (1 2 3 4 5 1 2 3 4 5))
-> (1 2 3 4 5 1 2 3 4 5)
: (and (member 3 L) (member 3 (cdr @)) (set @ 999))
-> 999
: L
-> (1 2 3 4 5 1 2 999 4 5)
These functions include
and,
case,
cond,
nond,
do,
for,
if,
if2,
ifn,
loop,
nand,
nor,
or,
prog1,
prog2,
state,
unless,
until,
when,
while,
and the bodies of *Run
tasks.
@
is generally local to functions and methods, its value is
automatically saved upon function entry and restored at exit.
In Pico Lisp, it is legal to compare data items of arbitrary type. Any two items are either
CAR
's are equal, their
CDR
's are compared). For differing types, the following rule
applies: Numbers are less than symbols, and symbols are less than lists. As
special cases, NIL
is always less than anything else, and
T
is always greater than anything else.
To demonstrate this, sort
a list of mixed
data types:
: (sort '("abc" T (d e f) NIL 123 DEF))
-> (NIL 123 DEF "abc" (d e f) T)
See also max
, min
, rank
, <
, =
, >
etc.
Pico Lisp comes with built-in object oriented extensions. There seems to be a common agreement upon three criteria for object orientation:
Pico Lisp implements both objects and classes with symbols. Object-local data
are stored in the symbol's property list, while the code (methods) and links to
the superclasses are stored in the symbol's VAL
(encapsulation).
In fact, there is no formal difference between objects and classes (except that objects usually are anonymous symbols containing mostly local data, while classes are named internal symbols with an emphasis on method definitions). At any time, a class may be assigned its own local data (class variables), and any object can receive individual method definitions in addition to (or overriding) those inherited from its (super)classes.
Pico Lisp supports multiple inheritance. The VAL
of each object
is a (possibly empty) association list of message symbols and method bodies,
concatenated with a list of classes. When a message is sent to an object, it is
searched in the object's own method list, and then (with a left-to-right
depth-first search) in the tree of its classes and superclasses. The first
method found is executed and the search stops. The search may be explicitly
continued with the extra
and super
functions.
Thus, which method is actually executed when a message is sent to an object depends on the classes that the object is currently linked to (polymorphism). As the method search is fully dynamic (late binding), an object's type (i.e. its classes and method definitions) can be changed even at runtime!
While a method body is being executed, the global variable This
is set to the current object, allowing the use of
the short-cut property functions =:
, :
and ::
.
On the lowest level, a Pico Lisp database is simply a collection of external symbols. They reside in a database file, and are
dynamically swapped in and out of memory. Only one database file (pool) can be
open at any time (pool
).
The symbols in the database can be used to store arbitrary information
structures. In typical use, some symbols represent nodes of search trees, by
holding keys, values, and links to subtrees in their VAL
's. Such a
search tree in the database is called index.
For the most part, other symbols in the database are objects derived from the
+Entity
class.
Entities depend on objects of the +Relation
class hierarchy.
Relation-objects manage the property values of entities, they define the
application database model and are responsible for the integrity of mutual
object references and index trees.
Relations are stored as properties in the entity classes, their methods are
invoked as daemons whenever property values in an entity are changed. When
defining an +Entity
class, relations are defined - in addition to
the method definitions of a normal class - with the rel
function. Predefined relation classes include
+Symbol
+String
+Number
+Date
+Time
+Blob
+Link
+Hook
+Joint
+List
+Bag
+Ref
+Key
+Idx
+Sn
+Bool
T
or NIL
+Any
A declarative language is built on top of Pico Lisp, that has the semantics of Prolog, but uses the syntax of Lisp.
For an explanation of Prolog's declarative programming style, an introduction like "Programming in Prolog" by Clocksin/Mellish (Springer-Verlag 1981) is recommended.
Facts and rules can be declared with the be
function. For example, a Prolog fact 'likes(john,mary).
' is written
in Pilog as:
(be likes (John Mary))
and a rule 'likes(john,X) :- likes(X,wine), likes(X,food).
' is
in Pilog:
(be likes (John @X) (likes @X wine) (likes @X food))
As in Prolog, the difference between facts and rules is that the latter ones
have conditions and usually contain variables. A variable in Pilog is any symbol
starting with an at-mark ("@
").
The cut operator of Prolog (usually written as an exclamation mark
(!
)) is the symbol T
in Pilog.
Pilog can be called from Lisp and vice versa:
goal
(prepare a query from Lisp data) and prove
(return an association list of successful
bindings).
CAR
of a Pilog clause is a Pilog variable, the
CDR
is executed as a Lisp expression and the result unified with
that variable.
->
function.
An interactive query can be done with the ?
function:
(? (likes John @X))
This will print all solutions, waiting for user input after each line. If a
non-empty line (not just a RETURN
key, but for example a dot
(.
) followed by RETURN
) is entered, it will terminate.
It was necessary to introduce - and adhere to - a set of conventions for Pico Lisp symbol names. Because all (internal) symbols have a global scope (there are no packages or name spaces), and each symbol can only have either a value or function definition, it would otherwise be very easy to introduce name conflicts. Besides this, source code readability is increased when the scope of a symbol is indicated by its name.
These conventions are not hard-coded into the language, but should be so into the head of the programmer. Here are the most commonly used ones:
*
"
_
"
+
"
>
"
For historical reasons, the global constant symbols T
and
NIL
do not obey these rules, and are written in upper case.
For example, a local variable could easily overshadow a function definition:
: (de max-speed (car)
(.. (get car 'speeds) ..) )
-> max-speed
Inside the body of max-speed
(and all other functions called
during that execution) the kernel function car
is redefined to some
other value, and will surely crash if something like (car Lst)
is
executed. Instead, it is safe to write:
: (de max-speed (Car) # 'Car' with upper case first letter
(.. (get Car 'speeds) ..) )
-> max-speed
Note that there are also some strict naming rules (as opposed to the voluntary conventions) that are required by the corresponding kernel functionalities, like:
@
" (see match and fill)
lib:sym
"
With that, the last of the above conventions (local functions start with an underscore) is not really necessary, because true local scope can be enforced with transient symbols.
Pico Lisp does not try very hard to be compatible with traditional Lisp systems. If you are used to some other Lisp dialects, you may notice the following differences:
CAR
and car
are different symbols,
which was not the case in traditional Lisp systems.
QUOTE
QUOTE
function returns its
first unevaluated argument. In Pico Lisp, on the other hand,
quote
returns all (unevaluated) argument(s).
LAMBDA
LAMBDA
function, in some way at the heart of traditional
Lisp, is completely missing (and quote
is used instead).
PROG
PROG
function of traditional Lisp, with its GOTO and RETURN
functionality, is also missing. Pico Lisp's prog
function is just a
simple sequencer (as PROGN
ins some Lisps).
This section provides a reference manual for the kernel functions, and some extensions. The first part is a thematically grouped list of indexes into the second part, which contains the function specifications in alphabetical order.
Though Pico Lisp is a dynamically typed language (resolved at runtime, as opposed to statically (compile-time) typed languages), many functions can only accept and/or return a certain set of data types. For each function, the expected argument types and return values are described with the following abbreviations:
The primary data types:
num
- Number
sym
- Symbol
lst
- List
Other (derived) data types
any
- Anything: Any primary data type
flg
- Flag: Boolean value (NIL
or non-NIL
)
cnt
- A count or a small number
dat
- Date: Days since first of March, in the year 0 A.D.
tim
- Time: Seconds since midnight
obj
- Object/Class: A symbol with methods and/or classes
var
- Variable: Either a symbol or a cell
exe
- Executable: A list as executable expression (eval
)
prg
- Prog-Body: A list of executable expressions (run
)
fun
- Function: Either a number (code-pointer), a symbol (message) or a list (lambda)
msg
- Message: A symbol sent to an object (to invoke a method)
cls
- Class: A symbol defined as an object's class
typ
- Type: A list of cls
symbols
pid
- Process ID: A number, the ID of a Unix process
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z Other
new
sym
str
char
name
sp?
pat?
fun?
intern
extern
====
box?
str?
ext?
touch
zap
length
size
format
chop
pack
glue
text
pre?
sub?
low?
upp?
lowc
uppc
fold
val
set
setq
def
de
dm
xchg
on
off
onOff
zero
one
default
let
let?
use
push
push1
pop
cut
del
queue
fifo
idx
lup
put
get
prop
=:
:
::
putl
getl
wipe
meta
atom
pair
lst?
num?
sym?
flg?
sp?
pat?
fun?
box?
str?
ext?
bool
not
==
n==
=
<>
=0
=T
n0
nT
<
<=
>
>=
match
+
-
*
/
%
*/
inc
dec
>>
lt0
ge0
gt0
abs
bit?
&
|
x|
sqrt
seed
rand
max
min
length
size
format
car
cdr
caar
cadr
cdar
cddr
caaar
caadr
cadar
caddr
cdaar
cdadr
cddar
cdddr
cadddr
cddddr
nth
con
cons
conc
circ
rot
list
need
make
made
chain
link
copy
mix
append
delete
delq
replace
strip
split
reverse
flip
trim
clip
head
tail
stem
fin
last
member
memq
mmeq
sect
diff
index
offset
assoc
asoq
rank
sort
length
size
val
set
xchg
push
push1
pop
cut
queue
fifo
idx
get
fill
apply
load
args
next
arg
rest
pass
quote
as
lit
eval
run
def
de
dm
box
new
type
isa
method
meth
send
try
super
extra
with
bind
job
let
let?
use
and
or
nand
nor
xor
bool
not
nil
t
prog
prog1
prog2
if
if2
ifn
when
unless
cond
nond,
case
state
while
until
loop
do
at
for
catch
throw
finally
!
e
$
sys
call
tick
kill
quit
fork
bye
apply
pass
all
maps
map
mapc
maplist
mapcar
mapcon
mapcan
filter
seek
find
pick
cnt
sum
maxi
mini
fish
by
path
in
out
pipe
ctl
any
sym
str
load
hear
tell
key
poll
peek
char
skip
eof
from
till
line
format
read
print
println
printsp
prin
prinl
space
flush
rewind
rd
pr
wr
rpc
wait
sync
echo
info
dir
lines
open
close
port
listen
accept
host
connect
nagle
udp
pool
journal
id
seq
lieu
lock
begin
commit
rollback
mark
free
dbck
rel
be
goal
prove
->
unify
?
stat
debug
trace
argv
opt
gc
raw
die
protect
heap
env
up
stk
stat
date
time
usec
stamp
pwd
cd
ctty
info
dir
call
tick
kill
quit
fork
bye
NIL
*DB
*Solo
^
@
@@
@@@
This
T
*Dbg
*PPid
*Pid
*Scl
*Class
*Run
*Led
*Err
*Rst
*Msg
*Uni
*Adr
*Fork
*Bye
(abs 'num) -> num
num
argument.
: (abs -7)
-> 7
: (abs 7)
-> 7
(accept 'cnt) -> cnt | NIL
cnt
(as received by
port
), and returns the new socket descriptor
cnt
. The global variable *Adr
is set to the IP address
of the client. See also listen
, connect
and *Adr
.
: (setq *Socket
(accept (port 6789)) ) # Accept connection at port 6789
-> 4
(all 'fun) -> any
fun
to all internal symbols in the system. Returns the
result of the last application.
: (all printsp) # Print the names of all internal symbols
delWord +PwField +Fmt tail char cons month ..
.. conc cond -> cond
# Find all symbols starting with an underscore character
: (make (all '((X) (and (= "_" (car (chop X))) (link X)))))
-> (_ed _isa _delL _delR _dbg _del _query _scan _hex _boxSend _put)
(and 'any ..) -> any
any
are evaluated from left to
right. If NIL
is encountered, NIL
is returned
immediately. Else the result of the last expression is returned.
: (and (= 3 3) (read))
abc # User input
-> abc
: (and (= 3 4) (read))
-> NIL
(any 'sym) -> any
any
from the name of sym
. See also sym
and str
.
: (any "(a b # Comment^Jc d)")
-> (a b c d)
: (any "\"A String\"")
-> "A String"
(append 'lst ..) -> lst
conc
.
: (append '(a b c) (1 2 3))
-> (a b c 1 2 3)
: (append (1) (2) (3) 4)
-> (1 2 3 . 4)
(apply 'fun 'lst ['any ..]) -> any
fun
to lst
. If additional any
arguments are given, they are applied as leading elements of lst
.
: (apply + (1 2 3))
-> 6
: (apply * (5 6) 3 4)
-> 360
: (apply '((X Y Z) (* X (+ Y Z))) (3 4 5))
-> 27
(arg ['cnt]) -> any
@
). If cnt
is not given, the value that was returned
from the last call to next
) is returned. Otherwise, the
cnt
'th remaining argument is returned. See also args
, next
, rest
and pass
.
: (de foo @ (println (next) (arg))) # Print argument twice
-> foo
: (foo 123)
123 123
-> 123
: (de foo @
(println (arg 1) (arg 2))
(println (next))
(println (arg 1) (arg 2)) )
-> foo
: (foo 'a 'b 'c)
a b
a
b c
-> c
(args) -> flg
@
). Returns T
when there are more arguments to be
fetched from the internal list. See also next
,
arg
, rest
and
pass
.
: (de foo @ (println (args))) # Test for arguments
-> foo
: (foo) # No arguments
NIL
-> NIL
: (foo NIL) # One argument
T
-> T
: (foo 123) # One argument
T
-> T
(argv [sym ..] [. sym]) -> lst|sym
argv
returns a list of strings
containing all remaining command line arguments. Otherwise, the sym
arguments are subsequently bound to the command line arguments. A hyphen
"-
" can be used to stop load
ing further arguments. See
also Invocation
and opt
.
$ ./p -"println 'Ok" - abc 123
Ok
: (argv)
-> ("abc" "123")
: (argv A B)
-> "123"
: A
-> "abc"
: B
-> "123"
: (argv . Lst)
-> ("abc" "123")
: Lst
-> ("abc" "123")
(as 'any1 . any2) -> any2 | NIL
any2
unevaluated when any1
evaluates to
non-NIL
. Otherwise NIL
is returned. (as Flg A B
C)
is equivalent to (and Flg '(A B C))
. See also quote
.
: (as (= 3 3) A B C)
-> (A B C)
(asoq 'any 'lst) -> lst
lst
with any
as its CAR
, or
NIL
if no match is found. ==
is used
for comparison (pointer equality). See also assoc
, delq
, memq
and mmeq
.
: (asoq 999 '((999 1 2 3) (b . 7) ("ok" "Hello")))
-> NIL
: (asoq 'b '((999 1 2 3) (b . 7) ("ok" "Hello")))
-> (b . 7)
(assoc 'any 'lst) -> lst
lst
with its CAR
equal to any
, or
NIL
if no match is found.
: (assoc "b" '((999 1 2 3) ("b" . 7) ("ok" "Hello")))
-> ("b" . 7)
: (assoc 999 '((999 1 2 3) ("b" . 7) ("ok" "Hello")))
-> (999 1 2 3)
: (assoc 'u '((999 1 2 3) ("b" . 7) ("ok" "Hello")))
-> NIL
(at '(cnt1 . cnt2) . prg) -> any
cnt1
(destructively), and returns NIL
when it is less than cnt2
. Otherwise, prg
is executed
and cnt1
is reset to zero. Returns the result of prg
.
: (do 11 (prin ".") (at (0 . 3) (prin "!")))
...!...!...!..-> NIL
(atom 'any) -> flg
T
when the argument any
is an atom (a
number or a symbol). See also pair
.
: (atom 123)
-> T
: (atom 'a)
-> T
: (atom NIL)
-> T
: (atom (123))
-> NIL
(be sym . any) -> sym
sym
argument, by concatenating the any
argument to the T
property of sym
. See also goal
and
prove
.
: (be likes (John Mary))
-> likes
: (be likes (John @X) (likes @X wine) (likes @X food))
-> likes
: (get 'likes T)
-> (((John Mary)) ((John @X) (likes @X wine) (likes @X food)))
: (? (likes John @X))
@X=Mary
-> NIL
(begin) -> T
commit
and rollback
.
: (pool "db")
-> T
: (put '{1} 'str "Hello") # Set property in first level
-> "Hello"
: (begin) # Start second level
-> T
: (put '{1} 'str "abc") # Set another value
-> "abc"
: (get '{1} 'str)
-> "abc"
: (rollback) # Rollback second level
-> NIL
: (get '{1} 'str) # Value is restored
-> "Hello"
: (rollback) # Rollback top level
-> T
: (get '{1} 'str) # Value is cleared
-> NIL
(bind 'sym|lst . prg) -> any
sym
must
evaluate to a symbol, a list of symbols, or to a list of symbol-value pairs. The
values of these symbols are saved (and the symbols bound to the values in the
last case), prg
is executed, then the symbols are restored to their
original values. During execution of prg
, the values of the symbols
can be temporarily modified. The return value is the result of prg
.
See also let
, job
and use
.
: (setq X 123) # X is 123
-> 123
: (bind 'X '((setq X "Hello") (println X))) # Set X to "Hello", print it
"Hello"
-> "Hello"
: (bind '((X . 3) (Y . 4)) '((println X Y) (* X Y)))
3 4
-> 12
: X
-> 123 # X is restored to 123
(bit? 'num ..) -> num | NIL
num
argument when all bits which are 1 in the
first argument are also 1 in all following arguments. See also &
, |
and x|
.
: (bit? 7 15 255)
-> 7
: (bit? 1 3)
-> 1
: (bit? 1 2)
-> NIL
(bool 'any) -> flg
T
when the argument any
is
non-NIL
. This function is only needed when T
is
strictly required for a "true" condition (Usually, any non-NIL
value is considered to be "true"). See also flg?
.
: (and 3 4)
-> 4
: (bool (and 3 4))
-> T
(box 'any) -> sym
any
argument. See also new
and
box?
.
: (show (box '(A B C)))
$134425627 (A B C)
-> $134425627
(box? 'any) -> sym | NIL
any
when it is an anonymous symbol,
otherwise NIL
. See also box
,
str?
and ext?
.
: (box? (new))
-> $134563468
: (box? 123)
-> NIL
: (box? 'a)
-> NIL
: (box? NIL)
-> NIL
(by 'fun1 'fun2 'lst ..) -> lst
fun1
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun1
. Each result of fun1
is CONSed with its
corresponding argument form the original lst
, and collected into a
list which is passed to fun2
. For the list returned from
fun2
, the CAR elements returned by fun1
are
(destructively) removed from each element.
: (let (A 1 B 2 C 3) (by val sort '(C A B)))
-> (A B C)
: (by '((N) (bit? 1 N)) group (3 11 6 2 9 5 4 10 12 7 8 1))
-> ((3 11 9 5 7 1) (6 2 4 10 12 8))
(bye 'cnt|NIL)
finally
expressions, then the VAL
of the global variable *Bye
(should be a prg
), closes all open
files, and exits the Pico Lisp interpreter. The process return value is
cnt
, or 0 if the argument is missing or NIL
.
: (setq *Bye '((println 'Ok) (println 'bye)))
-> ((println 'Ok) (println 'bye))
: (bye)
Ok
bye
$
(caaar 'lst) -> any
(car (car (car 'lst)))
.
: (caaar '(((1 2) 3) 4))
-> 1
(caadr 'lst) -> any
(car (car (cdr 'lst)))
.
: (caadr '(1 (2 3)))
-> 2
(caar 'lst) -> any
(car (car 'lst))
.
: (caar '((1 2) (3 4)))
-> 1
(cadar 'lst) -> any
(car (cdr (car 'lst)))
.
: (cadar '((1 2 3)))
-> 2
(cadddr 'lst) -> any
(car (cdr (cdr (cdr
'lst))))
, or the fourth element of lst
.
: (cadddr (1 2 3 4 5 6))
-> 4
(caddr 'lst) -> any
(car (cdr (cdr 'lst)))
, or
the third element of lst
.
: (caddr (1 2 3 4 5 6))
-> 3
(cadr 'lst) -> any
(car (cdr 'lst))
, or the
second element of lst
.
: (cadr (1 2 3 4 5 6))
-> 2
(call 'any ..) -> flg
any
arguments specify the
command and its arguments. Returns T
if the command was executed
successfully.
: (when (call 'test "-r" "file.l") # Test if file exists and is readable
(load "file.l") # Load it
(call 'rm "file.l") ) # Remove it
(car 'lst) -> any
lst
.
: (car (1 2 3 4 5 6))
-> 1
(case 'any (any1 . prg1) (any2 . prg2) ..) -> any
any
is evaluated and compared to the
CAR
elements anyN
of each clause. If one of them is a
list, any
is in turn compared to all elements of that list.
T
is a catch-all for any value. If a comparison succeeds,
prgN
is executed, and the result returned. Otherwise
NIL
is returned.
: (case (char 66) ("A" (+ 1 2 3)) (("B" "C") "Bambi") ("D" (* 1 2 3)))
-> "Bambi"
(catch 'sym . prg) -> any
throw
. sym
is used by throw
as a jump label (with T
being a catch-all for any label). If
throw
is called during the execution of prg
, the value
thrown is returned immediately. Otherwise, the result of prg
is
returned. See also finally
.
: (catch 'Ok (println 1) (throw 'Ok 999) (println 2))
1
-> 999
(cd 'any) -> sym
any
. The old directory is
returned on success, otherwise NIL
. See also dir
and pwd
.
: (when (cd "lib")
(println (sum lines (dir)))
(cd @) )
10955
(cdaar 'lst) -> any
(cdr (car (car 'lst)))
.
: (cdaar '(((1 2 3))))
-> (2 3)
(cdadr 'lst) -> any
(cdr (car (cdr 'lst)))
.
: (cdadr '((1 2) (3 4)))
-> (4)
(cdar 'lst) -> any
(cdr (car 'lst))
.
: (cdar '((1 2) (3 4)))
-> (2)
(cddar 'lst) -> any
(cdr (cdr (car 'lst)))
.
: (cddar '((1 2 3 4)))
-> (3 4)
(cddddr 'lst) -> any
(cdr (cdr (cdr (cdr
'lst))))
. Returns all but the first four elements of lst
.
: (cddddr (1 2 3 4 5 6))
-> (5 6)
(cdddr 'lst) -> any
(cdr (cdr (cdr 'lst)))
.
Returns all but the first three elements of lst
.
: (cdddr (1 2 3 4 5 6))
-> (4 5 6)
(cddr 'lst) -> any
(cdr (cdr 'lst))
. Returns
all but the first two elements of lst
.
: (cddr (1 2 3 4 5 6))
-> (3 4 5 6)
(cdr 'lst) -> any
lst
.
: (cdr (1 2 3 4 5 6))
-> (2 3 4 5 6)
(chain 'lst ..) -> lst
lst
to the end of the list in the current make
environment. This operation is efficient also for
long lists, because a pointer to the last element of the list is maintained.
chain
returns the last linked argument. See also link
and made
.
: (make (chain (list 1 2 3) NIL (cons 4)) (chain (list 5 6)))
-> (1 2 3 4 5 6)
(char) -> sym
(char 'cnt) -> sym
(char T) -> sym
(char 'sym) -> cnt
NIL
upon end of file. When called with a number cnt
, a character with
the corresponding unicode value is returned. As a special case, T
is accepted to produce a byte value greater than any first byte in a unicode
character (used as a top value in comparisons). Otherwise, when called with a
symbol sym
, the numeric unicode value of the first character of the
name of that symbol is returned. See also peek
,
skip
, key
,
line
, till
and
eof
.
: (char) # Read character from console
A # (typed 'A' and a space/return)
-> "A"
: (char 100) # Convert unicode to symbol
-> "d"
: (char T) # Special case, catch all
-> # (not printable)
: (char "d") # Convert symbol to unicode
-> 100
(chop 'any) -> lst
any
as a list of single-character strings. If
any
is NIL
or a symbol with no name, NIL
is returned. A list argument is returned unchanged.
: (chop 'car)
-> ("c" "a" "r")
: (chop "Hello")
-> ("H" "e" "l" "l" "o")
(circ 'any ..) -> lst
any
arguments by cons
ing them to a list and then connecting the
CDR
of the last cell to the first cell. See also list
.
: (circ 'a 'b 'c)
-> (a b c .)
(clip 'lst) -> lst
lst
with all white space characters or
NIL
elements removed from both sides. See also trim
.
: (clip '(NIL 1 NIL 2 NIL))
-> (1 NIL 2)
: (clip '(" " a " " b " "))
-> (a " " b)
(close 'cnt) -> flg
cnt
, and returns non-NIL
when successful. See also open
, listen
and connect
.
: (close 2) # Close standard error
-> T
(cnt 'fun 'lst ..) -> cnt
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns the count of non-NIL
values returned
from fun
.
: (cnt cdr '((1 . T) (2) (3 4) (5)))
-> 2
(commit ['any] [exe1] [exe2]) -> flg
begin
are taken into account. A non-NIL
any
argument forces modifications of the current transaction level
to be written out, even if this is not the top level. When any
is
anything other than T
, it is implicitly sent (with all modified
objects) via the tell
mechanism to all family
members. If exe1
or exe2
are given, they are executed
as pre- or post-expressions while the database is lock
ed and protect
ed. Returns T
when the topmost
transaction is closed. See also rollback
.
: (pool "db")
-> T
: (put '{1} 'str "Hello")
-> "Hello"
: (commit)
-> T
(con 'lst 'any) -> any
any
to the first cell of lst
, by
(destructively) storing any
in the CDR
of
lst
.
: (setq C (1 . a))
-> (1 . a)
: (con C '(b c d))
-> (b c d)
: C
-> (1 b c d)
(conc 'lst ..) -> lst
append
.
: (setq A (1 2 3) B '(a b c))
-> (a b c)
: (conc A B) # Concatenate lists in 'A' and 'B'
-> (1 2 3 a b c)
: A
-> (1 2 3 a b c) # Side effect: List in 'A' is modified!
(cond (('any1 . prg1) ('any2 . prg2) ..)) -> any
anyN
conditions evaluates
to non-NIL
, prgN
is executed and the result returned.
Otherwise (all conditions evaluate to NIL
), NIL
is
returned. See also nond
, if
, if2
and when
.
: (cond
((= 3 4) (println 1))
((= 3 3) (println 2))
(T (println 3)) )
2
-> 2
(connect 'any 'cnt) -> cnt | NIL
any
, port cnt
. any
may be either a
hostname or a standard internet address in numbers-and-dots notation. Returns a
socket descriptor cnt
, or NIL
if the connection cannot
be established. See also listen
and nagle
.
: (connect "localhost" 4444)
-> 3
(cons 'any 'any) -> lst
CAR
and the second argument in the CDR
.
: (cons 1 2)
-> (1 . 2)
: (cons 'a '(b c d))
-> (a b c d)
: (cons '(a b) '(c d))
-> ((a b) c d)
(copy 'any) -> any
any
. For lists, the top level cells are
copied, while atoms are returned unchanged.
: (=T (copy T)) # Atoms are not copied
-> T
: (setq L (1 2 3))
-> (1 2 3)
: (== L L)
-> T
: (== L (copy L)) # The copy is not identical to the original
-> NIL
: (= L (copy L)) # But the copy is equal to the original
-> T
(ctl 'sym . prg) -> any
sym
is "+
") can be set on the file
sym
, then executes prg
and releases the lock. If the
files does not exist, it will be created. When sym
is
NIL
, a shared lock is tried on the current innermost I/O channel,
and when it is T
, an exclusive lock is tried instead. See also
in
, pipe
and
out
. Note: It is not recommended to lock a file
by name and then do I/O on the same file, as this may give unexpected results on
some operating systems.
$ echo 9 >count # Write '9' to file "count"
$ ./p dbg.l
: (ctl ".ctl" # Exclusive control, using ".ctl"
(in "count"
(let Cnt (read) # Read '9'
(out "count"
(println (dec Cnt)) ) ) ) ) # Write '8'
-> 8
:
$ cat count # Check "count"
8
(ctty 'sym|pid) -> flg
ctty
changes the current
TTY device to sym
. Otherwise, the local console is prepared for
serving the remote Pico Lisp process pid
. See also raw
.
: (ctty "/dev/tty")
-> T
(cut 'cnt 'var) -> lst
cnt
elements (CAR
) from the stack
in var
. See also pop
and del
.
: (setq S '(1 2 3 4 5 6 7 8))
-> (1 2 3 4 5 6 7 8)
: (cut 3 'S)
-> (1 2 3)
: S
-> (4 5 6 7 8)
(date ['T]) -> dat
(date 'dat) -> (y m d)
(date 'y 'm 'd) -> dat | NIL
(date '(y m d)) -> dat | NIL
T
argument, the current Coordinated
Universal Time (UTC) is returned. When called with a single number
dat
, it is taken as a date and a list with the corresponding year,
month and day is returned. When called with three numbers (or a list of three
numbers) for the year, month and day, the corresponding date is returned (or
NIL
if they do not represent a legal date). See also time
.
: (date) # Today
-> 730589
: (date 2000 6 12) # 12-06-2000
-> 730589
: (date 2000 22 5) # Illegal date
-> NIL
: (date (date)) # Today's year, month and day
-> (2000 6 12)
: (- (date) (date 2000 1 1)) # Number of days since first of January
-> 163
(dbck ['cnt] 'flg) -> any
cnt
'th)
database file, and returns NIL
(or the number of blocks and symbols
if flg
is non-NIL
) if everything seems correct.
Otherwise, a string indicating an error is returned. As a side effect, possibly
unused blocks (as there might be when a rollback
is done before commit
ing newly allocated (new
) external symbols) are appended to the free list.
: (pool "db")
-> T
: (dbck)
-> NIL
(de sym . any) -> sym
sym
argument, by setting its
VAL
to the any
argument. If the symbol has already
another value, a "redefined" message is issued. de
is the standard
way to define a function.
: (de foo (X Y) (* X (+ X Y))) # Define a function
-> foo
: (foo 3 4)
-> 21
: (de *Var . 123) # Define a variable value
: *Var
-> 123
(debug 'sym) -> T
(debug 'sym 'cls) -> T
(debug '(sym . cls)) -> T
!
breakpoint function call at the
beginning and all top-level expressions of the function or method body of
sym
, to allow a stepwise execution. Typing (d)
at a
breakpoint will also debug the current subexpression, and (e)
will evaluate the current subexpression. The current
subexpression is stored in the global variable ^
.
See also *Dbg
.
: (de tst (N) # Define tst
(println (+ 3 N)) )
-> tst
: (debug 'tst) # Set breakpoints
-> T
: (pp 'tst)
(de tst (N)
(! println (+ 3 N)) ) # Breakpoint '!'
-> tst
: (tst 7) # Execute
(println (+ 3 N)) # Stopped at beginning of 'tst'
! (d) # Debug subexpression
-> T
! # Continue
(+ 3 N) # Stopped in subexpression
! N # Inspect variable 'N'
-> 7
! # Continue
10 # Output of print statement
-> 10 # Done
: (unbug 'tst)
-> T
: (pp 'tst) # Restore to original
(de tst (N)
(println (+ 3 N)) )
-> tst
(dec 'num) -> num
(dec 'var ['num]) -> num
num
decremented by 1. The
second form decrements the VAL
of var
by 1, or by
num
. (dec 'num)
is equivalent to (- 'num
1)
and (dec 'var)
is equivalent to (set 'var (- var
1))
.
: (dec -1)
-> -2
: (dec 7)
-> 6
: (setq N 7)
-> 7
: (dec 'N)
-> 6
: (dec 'N 3)
-> 3
(def 'sym 'any) -> sym
(def 'sym 'sym 'any) -> sym
sym
argument,
by setting its VAL
's to any
. The second form defines a
property value any
for the second argument's sym
key.
If any of these values existed and was changed in the process, a "redefined"
message is issued.
: (def 'b '((X Y) (* X (+ X Y))))
-> b
: (def 'b 999)
# b redefined
-> b
(default sym 'any ..) -> any
any
in the sym
arguments only if
their current values are NIL
. Otherwise, their values are left
unchanged. default
is used typically in functions to initialize
optional arguments.
: (de foo (A B) # Function with two optional arguments
(default A 1 B 2) # The default values are 1 and 2
(list A B) )
-> foo
: (foo 333 444) # Called with two arguments
-> (333 444)
: (foo 333) # Called with one arguments
-> (333 2)
: (foo) # Called without arguments
-> (1 2)
(del 'any 'var) -> any
any
from the list in the value of var
.
(del 'any 'var)
is equivalent to (set 'var (delete 'any
var))
. See also delete
, cut
and pop
.
: (setq S '((a b c) (d e f)))
-> ((a b c) (d e f))
: (del '(d e f) 'S)
-> ((a b c))
: (del 'b S)
-> (a c)
(delete 'any 'lst) -> lst
any
from lst
. If any
is
contained more than once in lst
, only the first occurrence is
deleted. See also delq
.
: (delete 2 (1 2 3))
-> (1 3)
: (delete (3 4) '((1 2) (3 4) (5 6) (3 4)))
-> ((1 2) (5 6) (3 4))
(delq 'any 'lst) -> lst
any
from lst
. If any
is
contained more than once in lst
, only the first occurrence is
deleted. ==
is used for comparison (pointer
equality). See also delete
, asoq
, memq
and mmeq
.
: (delq 'b '(a b c))
-> (a c)
: (delq 2 (1 2 3))
-> (1 2 3)
(die 'cnt . prg) -> any
prg
does not finish within
cnt
seconds, the current process will receive a SIGTERM signal. See
also bye
and protect
.
: (die 6 (finally (msg 'Bye) (loop)))
Bye
$
(diff 'lst 'lst) -> lst
lst
arguments. See also sect
.
: (diff (1 2 3 4 5) (2 4))
-> (1 3 5)
: (diff (1 2 3) (1 2 3))
-> NIL
(dir ['any]) -> lst
any
. Names
starting with a dot '.
' are ignored. See also cd
and info
.
: (filter '((F) (tail '(. c) (chop F))) (dir "src/"))
-> ("main.c" "subr.c" "gc.c" "io.c" "big.c" "sym.c" "tab.c" "flow.c" ..
(dm sym . fun) -> sym
(dm (sym . cls) . fun) -> sym
(dm (sym sym [. cls]) . fun) -> sym
sym
in the current class,
implicitly given by the value of the global variable *Class
, or -
in the second form - for the explicitly given class cls
. In the
third form, the class object is obtained by get
ing sym
from *Class
(or
cls
if given).
: (dm start> ()
(super)
(mapc 'start> (: fields))
(mapc 'start> (: arrays)) )
(do 'flg|num ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any
num
times (or never (if the first argument is NIL
), or
an infinite number of times (if the first argument is T
)). If a
clause has NIL
or T
as its CAR
, the
clause's second element is evaluated as a condition and - if the result is
NIL
or non-NIL
, respectively - the prg
is
executed and the result returned. Otherwise (if count drops to zero), the result
of the last expression is returned. See also loop
and for
.
: (do 4 (printsp 'Ok))
Ok Ok Ok Ok -> Ok
: (do 4 (printsp 'Ok) (T (= 3 3) (printsp 'done)))
Ok done -> done
(e . prg) -> any
prg
in the execution
environment, or the currently executed expression if prg
is not
given. See also debug
, !
, ^
and *Dbg
.
: (! + 3 4)
(+ 3 4)
! (e)
-> 7
(echo ['cnt ['cnt]] | ['sym ..]) -> sym
cnt
is given, only that many bytes are actually echoed. In case
of two cnt
arguments, the first one specifies the number of bytes
to skip in the input stream. Otherwise, if one or more sym
arguments are given, the echo process stops as soon as one of the symbol's names
is encountered in the input stream (in that case, the name will be read (and
returned), but not written). Returns non-NIL
if the operation was
successfully completed.
: (in "x.l" (echo)) # Display file on console
..
: (out "x2.l" (in "x.l" (echo))) # Copy file "x.l" to "x2.l"
(env ['lst] | ['sym 'val] ..) -> lst
lst
, or the
explicitly given sym
-val
pairs. See also stk
, bind
and job
.
: (env)
-> NIL
: (let (A 1 B 2) (env))
-> ((A . 1) (B . 2))
: (let (A 1 B 2) (env '(A B)))
-> ((B . 2) (A . 1))
: (let (A 1 B 2) (env 'X 7 '(A B) 'Y 8))
-> ((Y . 8) (B . 2) (A . 1) (X . 7))
(eof ['flg]) -> flg
flg
is non-NIL
, the channel's status is forced to
end-of-file, so that the next call to eof
will return
T
, and calls to char
, peek
, line
, from
, till
, read
or skip
will
return NIL
. Note that eof
cannot be used with
the binary rd
function.
: (in "file" (until (eof) (println (line T))))
...
(eval 'any ['cnt]) -> any
any
. Note that because of the standard argument
evaluation, any
is actually evaluated twice. If a binding
environment offset cnt
is given, the second evaluation takes place
in the corresponding environment. See also run
and up
.
: (eval (list '+ 1 2 3))
-> 6
: (setq X 'Y Y 7)
-> 7
: X
-> Y
: Y
-> 7
: (eval X)
-> 7
(ext? 'any) -> sym | NIL
any
when it is an existing external
symbol, otherwise NIL
. See also sym?
, box?
, str?
, extern
and
lieu
.
: (ext? *DB)
-> {1}
: (ext? 'abc)
-> NIL
: (ext? "abc")
-> NIL
: (ext? 123)
-> NIL
(extern 'sym) -> sym | NIL
sym
is already extern, it is returned. Otherwise, a new external
symbol is returned. NIL
is returned if sym
does not
exist in the database. See also intern
and
ext?
.
: (extern "A1b")
-> {A1b}
: (extern "{A1b}")
-> {A1b}
(extra ['any ..]) -> any
This
, this time starting the search for a method at the
remaining branches of the inheritance tree of the class where the current method
was found.
(dm key> (C) # 'key>' method of the '+Uppc' class
(uppc (extra C)) ) # Convert 'key>' of extra classes to upper case
(fifo 'var ['any]) -> any
any
argument, it will be concatenated to end of the
structure. Otherwise, the first element is removed from the structure and
returned. See also queue
, push
, pop
, rot
and circ
.
: (fifo 'X 1)
-> 1
: (fifo 'X 2)
-> 2
: (fifo 'X 3)
-> 3
: X
-> (3 1 2 .)
: (fifo 'X)
-> 1
: (fifo 'X)
-> 2
: X
-> (3 .)
(fill 'any ['sym|lst]) -> any
any
, by substituting sym
, or all
symbols in lst
, or - if no second argument is given - each pattern
symbol in any
(see pat?
), with its
current value. In that case, @
itself is not considered a pattern
symbol. See also match
.
: (setq @X 1234 @Y (1 2 3 4))
-> (1 2 3 4)
: (fill '@X)
-> 1234
: (fill '(a b (c @X) ((@Y . d) e)))
-> (a b (c 1234) (((1 2 3 4) . d) e))
: (let X 2 (fill (1 X 3) 'X))
-> (1 2 3)
(filter 'fun 'lst ..) -> lst
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns a list of all elements of lst
where
fun
returned non-NIL
. See also fish
.
: (filter num? (1 A 2 (B) 3 CDE))
-> (1 2 3)
(fin 'any) -> num|sym
any
if it is an atom, otherwise the CDR
of
its last cell. See also last
and tail
.
: (fin 'a)
-> a
: (fin '(a . b))
-> b
: (fin '(a b . c))
-> c
: (fin '(a b c))
-> NIL
(finally exe . prg) -> any
prg
is executed, then exe
is evaluated, and the
result of prg
is returned. exe
will also be evaluated
if prg
does not terminate normally due to a runtime error or a call
to throw
. See also bye
, catch
, quit
and Error
Handling
.
: (finally (prinl "Done!")
(println 123)
(quit)
(println 456) )
123
Done!
: (catch 'A
(finally (prinl "Done!")
(println 1)
(throw 'A 123)
(println 2) ) )
1
Done!
-> 123
(find 'fun 'lst ..) -> any
fun
to successive elements of lst
until
non-NIL
is returned. Returns that element, or NIL
if
fun
did not return non-NIL
for any element of
lst
. When additional lst
arguments are given, their
elements are also passed to fun
. See also seek
, pick
.
: (find pair (1 A 2 (B) 3 CDE))
-> (B)
: (find '((A B) (> A B)) (1 2 3 4 5 6) (6 5 4 3 2 1))
-> 4
: (find > (1 2 3 4 5 6) (6 5 4 3 2 1)) # shorter
-> 4
(fish 'fun 'any) -> lst
fun
to each element - and recursively to all sublists -
of lst
. Returns a list of all items where fun
returned
non-NIL
. See also filter
.
: (fish gt0 '(a -2 (1 b (-3 c 2)) 3 d -1))
-> (1 2 3)
: (fish sym? '(a -2 (1 b (-3 c 2)) 3 d -1))
-> (a b c d)
(flg? 'any) -> flg
T
when the argument any
is either
NIL
or T
. See also bool
. (flg? X)
is equivalent to (or
(not X) (=T X))
.
: (flg? (= 3 3))
-> T
: (flg? (= 3 4))
-> T
: (flg? (+ 3 4))
-> NIL
(flip 'lst) -> lst
lst
(destructively) reversed. See also reverse
.
: (flip (1 2 3 4))
-> (4 3 2 1)
(flush) -> flg
flush
for standard output is done automatically before a call to
key
. Returns T
when successful. See
also rewind
.
: (flush)
-> T
(fold 'any ['cnt]) -> sym
any
is not a symbol,
NIL
is returned. Otherwise, a new transient symbol with all digits
and all letters of any
, converted to lower case, is returned. If
the cnt
argument is given, the result is truncated to that length
(or not truncated if cnt
is zero). Otherwise cnt
defaults to 24. See also lowc
.
: (fold " 1A 2-b/3")
-> "1a2b3"
: (fold " 1A 2-B/3" 3)
-> "1a2"
(for sym|(sym2 . sym) 'lst ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any
(for (sym|(sym2 . sym) 'any1 'any2 [. prg]) ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any
sym
is saved, sym
is
subsequently bound to the elements of lst
, and the body is executed
each time. In the second form, the value of sym
is saved, and
sym
is bound to any1
. If sym2
is given,
it is treated as a counter variable, first bound to 1 and then incremented for
each execution of the body. While the condition any2
evaluates to
non-NIL
, the body is repeatedly executed and, if prg
is given, sym
is re-bound to the result of its evaluation. If a
clause has NIL
or T
as its CAR
, the
clause's second element is evaluated as a condition and - if the result is
NIL
or non-NIL
, respectively - the prg
is
executed and the result returned. If the body is never executed,
NIL
is returned. See also do
and
loop
.
: (for (N 1 (>= 8 N) (inc N)) (printsp N))
1 2 3 4 5 6 7 8 -> 8
: (for (L (1 2 3 4 5 6 7 8) L) (printsp (pop 'L)))
1 2 3 4 5 6 7 8 -> 8
: (for X (1 a 2 b) (printsp X))
1 a 2 b -> b
: (for ((I . L) '(a b c d e f) L (cddr L)) (println I L))
1 (a b c d e f)
2 (c d e f)
3 (e f)
-> (e f)
: (for (I . X) '(a b c d e f) (println I X))
1 a
2 b
3 c
4 d
5 e
6 f
-> f
(fork) -> pid | NIL
NIL
in the child, and the
child's process ID pid
in the parent. In the child, the
VAL
of the global variable *Fork
(should be a prg
) is executed. See also pipe
and tell
.
: (unless (fork) (do 5 (println 'Ok) (wait 1000)) (bye))
-> NIL
Ok # Child's output
: Ok
Ok
Ok
Ok
(format 'num ['cnt ['sym1 ['sym2]]]) -> sym
(format 'sym ['cnt ['sym1 ['sym2]]]) -> num
num
to a string, or a string sym
to a number. In both cases, optionally a precision cnt
, a
decimal-separator sym1
and a thousands-separator sym2
can be supplied. Returns NIL
if the conversion is unsuccessful. See
also Numbers
.
: (format 123456789) # Integer conversion
-> "123456789"
: (format 123456789 2) # Fixed point
-> "1234567.89"
: (format 123456789 2 ",") # Comma as decimal-separator
-> "1234567,89"
: (format 123456789 2 "," ".") # and period as thousands-separator
-> "1.234.567,89"
:
: (format "123456789") # String to number
-> 123456789
: (format "1234567.89" 4) # scaled to four digits
-> 12345678900
: (format "1.234.567,89") # separators not recognized
-> NIL
: (format "1234567,89" 4 ",")
-> 12345678900
: (format "1.234.567,89" 4 ",") # thousands-separator not recognized
-> NIL
: (format "1.234.567,89" 4 "," ".")
-> 12345678900
(free 'cnt) -> (sym . lst)
cnt
'th database file, the next available
symbol sym
(i.e. the first symbol greater than any symbol in the
database), and the list lst
of free symbols. See also seq
, zap
and dbck
.
: (pool "x") # A new database
-> T
: (new T) # Create a new symbol
-> {2}
: (new T) # Create another symbol
-> {3}
: (commit) # Commit changes
-> T
: (zap '{2}) # Delete the first symbol
-> {2}
: (free 1) # Show free list
-> ({4}) # {3} was the last symbol allocated
: (commit) # Commit the deletion of {2}
-> T
: (free 1) # Now {2} is in the free list
-> ({4} {2})
(from 'any ..) -> sym
any
is
found, and starts subsequent reading from that point. The found any
argument, or NIL
(if none is found) is returned. See also till
and echo
.
: (and (from "val='") (till "'" T))
test val='abc'
-> "abc"
(fun? 'any) -> any
NIL
when the argument any
is neither a
number suitable for a code-pointer, nor a list suitable for a lambda expression
(function). Otherwise a number is returned for a code-pointer, T
for a function without arguments, and a single formal parameter or a list of
formal parameters for a function.
: (fun? 1000000000) # Might be a code pointer
-> 1000000000
: (fun? 100000000000000) # Too big for a code pointer
-> NIL
: (fun? 1000000001) # Cannot be a code pointer (odd)
-> NIL
: (fun? '((A B) (* A B))) # Lambda expression
-> (A B)
: (fun? '((A B) (* A B) . C)) # Not a lambda expression
-> NIL
: (fun? '(1 2 3 4)) # Not a lambda expression
-> NIL
: (fun? '((A 2 B) (* A B))) # Not a lambda expression
-> NIL
(gc ['cnt]) -> cnt | NIL
cnt
is given, so many
millions of free cells are reserved, increasing the heap size if necessary.
: (gc)
-> NIL
: (stat)
2 3%
-> 53299
: (gc 4)
-> 4
: (stat)
5 1%
-> 53322
(ge0 'any) -> num | NIL
num
when the argument is a number and greater or equal
zero, otherwise NIL
. See also gt0
,
lt0
, =0
and
n0
.
: (ge0 -2)
-> NIL
: (ge0 3)
-> 3
: (ge0 0)
-> 0
(get 'sym1|lst ['sym2|cnt ..]) -> any
any
from the properties of a symbol, or from a
list. From the first argument sym1|lst
, values are retrieved in
successive steps by either extracting the value (if the next argument is zero)
or a property (if the next argument is a symbol) from a symbol, the asoq
ed element (if the next argument is a symbol), the
n'th element (if the next argument is a positive number) or the n'th
CDR
(if the next argument is a negative number) from a list. See
also put
and :
.
: (put 'X 'a 1)
-> 1
: (get 'X 'a)
-> 1
: (put 'Y 'link 'X)
-> X
: (get 'Y 'link)
-> X
: (get 'Y 'link 'a)
-> 1
: (get '((a (b . 1) (c . 2)) (d (e . 3) (f . 4))) 'a 'b)
-> 1
: (get '((a (b . 1) (c . 2)) (d (e . 3) (f . 4))) 'd 'f)
-> 4
: (get '(X Y Z) 2)
-> Y
: (get '(X Y Z) 2 'link 'a)
-> 1
(getl 'sym1|lst1 ['sym2|cnt ..]) -> lst
lst
from a symbol. That
symbol is sym1
(if no other arguments are given), or a symbol found
by applying the get
algorithm to
sym1|lst1
and the following arguments. See also putl
and maps
.
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (put 'X 'flg T)
-> T
: (getl 'X)
-> (flg (2 . b) (1 . a))
(glue 'any 'lst) -> sym
pack
ing the any
argument between the
individual elements of lst
. See also text
.
: (glue "," '(a b c d))
-> "a,b,c,d"
(goal '([sym 'any ..] . lst) ['sym 'any ..]) -> lst
lst
. The head of the argument list may consist of a sequence of
symbols and expressions, which are used together with the optional
sym
and any
arguments to form an initial environment.
See also prove
.
: (goal '((likes John @X)))
-> (((1 (0) NIL ((likes John @X)) NIL T)))
: (goal '(@X 'John (likes @X @Y)))
-> (((1 (0) NIL ((likes @X @Y)) NIL ((0 . @X) 1 . John) T)))
(gt0 'any) -> num | NIL
num
when the argument is a number and greater than
zero, otherwise NIL
. See also ge0
,
lt0
, =0
and
n0
.
: (gt0 -2)
-> NIL
: (gt0 3)
-> 3
(head 'cnt|lst 'lst) -> lst
cnt
elements of
lst
. If cnt
is negative, it is added to the length of
lst
. If the first argument is a lst
, head
is a predicate function returning that argument list if it is equal
to the head of the second argument, and NIL
otherwise. See also
tail
.
: (head 3 '(a b c d e f))
-> (a b c)
: (head 0 '(a b c d e f))
-> NIL
: (head 10 '(a b c d e f))
-> (a b c d e f)
: (head -2 '(a b c d e f))
-> (a b c d)
: (head '(a b c) '(a b c d e f))
-> (a b c)
(heap 'flg) -> cnt
flg
is NIL
), or the total number of cells in
the system (if flg
is non-NIL
).
: (heap)
-> 126999
: (heap T)
-> 262144
(hear 'num|sym) -> any
num
, or opens the file
sym
, as an asynchronous command input channel. Any executable list
received via this channel will be executed in the background. As this mechanism
is also used for inter-family communication (see tell
), hear
is usually only called
explicitly by a top level parent process.
: (hear "fifo/cmd")
-> "fifo/cmd"
(host 'any) -> sym
*Adr
.
: (host "217.160.106.89")
-> "software-lab.biz"
(id 'num 'num) -> sym
(id 'sym [NIL]) -> num
(id 'sym T) -> (num . num)
: (id 1 2)
-> {1-2}
: (id '{1-2})
-> 2
: (id '{1-2} T)
-> (1 . 2)
(idx 'var 'any 'flg) -> lst
(idx 'var 'any) -> lst
(idx 'var) -> lst
var
, and checks for the existence of
any
. If any
is contained in var
, the
corresponding subtree is returned, otherwise NIL
. In the first
form, any
is destructively inserted into the tree if
flg
is non-NIL
, or deleted from the tree if
flg
is NIL
. The second form only checks for existence,
but does not change the index tree. In the third form (when called with a single
var
argument) the contents of the tree are returned as a sorted
list. If all elements are inserted in sorted order, the tree degenerates into a
linear list. See also lup
, sort
and member
.
: (idx 'X 'd T) # Insert data
-> NIL
: (idx 'X 2 T)
-> NIL
: (idx 'X '(a b c) T)
-> NIL
: (idx 'X 17 T)
-> NIL
: (idx 'X 'A T)
-> NIL
: (idx 'X 'd T)
-> (d (2 NIL 17 NIL A) (a b c)) # 'd' already existed
: (idx 'X T T)
-> NIL
: X # View the index tree
-> (d (2 NIL 17 NIL A) (a b c) NIL T)
: (idx 'X 'A) # Check for 'A'
-> (A)
: (idx 'X 'B) # Check for 'B'
-> NIL
: (idx 'X)
-> (2 17 A d (a b c) T) # Get list
: (idx 'X 17 NIL) # Delete '17'
-> (17 NIL A)
: X
-> (d (2 NIL A) (a b c) NIL T) # View it again
: (idx 'X)
-> (2 A d (a b c) T) # '17' is deleted
(if 'any1 'any2 . prg) -> any
any1
evaluates to
non-NIL
, any2
is evaluated and returned. Otherwise,
prg
is executed and the result returned. See also cond
, when
and if2
.
: (if (> 4 3) (println 'Ok) (println 'Bad))
Ok
-> Ok
: (if (> 3 4) (println 'Ok) (println 'Bad))
Bad
-> Bad
(if2 'any1 'any2 'any3 'any4 'any5 . prg) -> any
any1
and any2
evaluate to non-NIL
,
any3
is evaluated and returned. Otherwise, any4
or
any5
is evaluated and returned if any1
or
any2
evaluate to non-NIL
, respectively. If none of the
conditions evaluate to non-NIL
, prg
is executed and
the result returned. See also if
and cond
.
: (if2 T T 'both 'first 'second 'none)
-> both
: (if2 T NIL 'both 'first 'second 'none)
-> first
: (if2 NIL T 'both 'first 'second 'none)
-> second
: (if2 NIL NIL 'both 'first 'second 'none)
-> none
(ifn 'any1 'any2 . prg) -> any
any1
evaluates to NIL
, any2
is evaluated and returned.
Otherwise, prg
is executed and the result returned.
: (ifn (= 3 4) (println 'Ok) (println 'Bad))
Ok
-> Ok
(in 'any . prg) -> any
any
as input channel during the execution of
prg
. The current input channel will be saved and restored
appropriately. If the argument is NIL
, standard input is used. If
the argument is a symbol, it is used as a file name (opened for reading
and writing if the first character is "+
"). If it is a
number, it is used as the descriptor of an open file. Otherwise (if it is a
list), it is taken as a command with arguments, and a pipe is opened for input.
See also call
, load
, out
, pipe
and ctl
.
: (in "a" (list (read) (read) (read))) # Read three items from file "a"
-> (123 (a b c) def)
(inc 'num) -> num
(inc 'var ['num]) -> num
num
incremented by 1. The
second form increments the VAL
of var
by 1, or by
num
. (inc 'num)
is equivalent to (+ 'num
1)
and (inc 'var)
is equivalent to (set 'var (+ var
1))
.
: (inc 7)
-> 8
: (inc -1)
-> 0
: (zero N)
-> 0
: (inc 'N)
-> 1
: (inc 'N 7)
-> 8
: N
-> 8
: (setq L (1 2 3 4))
-> (1 2 3 4)
: (inc (cdr L))
-> 3
: L
-> (1 3 3 4)
(index 'any 'lst) -> cnt | NIL
cnt
position of any
in
lst
, or NIL
if it is not found. See also offset
.
: (index 'c '(a b c d e f))
-> 3
: (index '(5 6) '((1 2) (3 4) (5 6) (7 8)))
-> 3
(info 'any) -> (cnt|T dat . tim)
any
: The current
size cnt
in bytes, and the modification date and time (UTC). For
directories, T
is returned instead of the a size. See also dir
, date
, time
and lines
.
$ ls -l x.l
-rw-r--r-- 1 abu users 208 Jun 17 08:58 x.l
$ ./p dbg.l
: (info "x.l")
-> (208 730594 . 32315)
: (stamp 730594 32315)
-> "2000-06-17 08:58:35"
(intern 'sym) -> sym
sym
is already intern, it is returned. Otherwise, sym
is interned and returned. See also zap
, extern
and ====
.
: (intern "abc")
-> abc
: (intern 'car)
-> car
: ((intern (pack "c" "a" "r")) (1 2 3))
-> 1
(isa 'cls|typ 'any) -> flg
T
when any
is an object that inherits from
cls
or type
. See also type
.
: (isa '+Address Obj)
-> T
: (isa '(+Male +Person) Obj)
-> NIL
(job 'lst . prg) -> any
lst
). The current values of all symbols are saved, the
symbols are bound to the values in lst
, prg
is
executed, then the (possibly modified) symbol values are (destructively) stored
in the environment list, and the symbols are restored to their original values.
The return value is the result of prg
. Typically used in a *Run
task. See also env
,
bind
, let
,
use
and state
.
: (de tst ()
(job '((A . 0) (B . 0))
(println (inc 'A) (inc 'B 2)) ) )
-> tst
: (tst)
1 2
-> 2
: (tst)
2 4
-> 4
: (tst)
3 6
-> 6
: (pp 'tst)
(de tst NIL
(job '((A . 3) (B . 6))
(println (inc 'A) (inc 'B 2)) ) )
-> tst
(journal) -> T
pool
.
: (in "db.log" (journal))
-> T
(key ['cnt]) -> sym
select
system call is executed for all file descriptors and
timers in the VAL
of the global variable *Run
. If cnt
is non-NIL
, that
amount of milliseconds is waited maximally, and NIL
is returned
upon timeout. See also raw
and wait
.
: (key) # Wait for a key
-> "a" # 'a' pressed
(kill 'pid ['cnt]) -> flg
cnt
(or SIGTERM if
cnt
is not given) to the process with the ID pid
.
Returns T
if successful.
: (kill *Pid 20) # Stop current process
[2]+ Stopped bin/picolisp # Unix shell
$ fg # Job control: Foreground
bin/picolisp
-> T # 'kill' was successful
(last 'lst) -> any
lst
. See also fin
and tail
.
: (last (1 2 3 4))
-> 4
: (last '((a b) c (d e f)))
-> (d e f)
(length 'any) -> cnt | T
any
. For numbers this is the number of
digits in the value (plus 1 for negative values), for symbols it is the number
of characters in the name, and for lists it is the number of elements (or
T
for circular lists). See also size
.
: (length "abc")
-> 3
: (length "äbc")
-> 3
: (length 123)
-> 3
: (length (1 (2) 3))
-> 3
: (length (1 2 3 .))
-> T
(let sym 'any . prg) -> any
(let (sym 'any ..) . prg) -> any
sym
- or the
values of the symbols sym
in the list of the second form - are
saved and the symbols are bound to the evaluated any
arguments.
prg
is executed, then the symbols are restored to their original
values. The result of prg
is returned. It is an error condition to
pass NIL
as a sym
argument. See also let?
, bind
, job
and use
.
: (setq X 123 Y 456)
-> 456
: (let X "Hello" (println X))
"Hello"
-> "Hello"
: (let (X "Hello" Y "world") (prinl X " " Y))
Hello world
-> "world"
: X
-> 123
: Y
-> 456
(let? sym 'any . prg) -> any
any
evalutes to NIL
, NIL
is returned. Otherwise, the value
of the symbol sym
is saved and sym
is bound to the
evaluated any
argument. prg
is executed, then
sym
is restored to its original value. The result of
prg
is returned. It is an error condition to pass NIL
as the sym
argument. (let? sym 'any ..)
is equivalent
to (when 'any (let sym @ ..))
. See also let
, bind
, job
and use
.
: (setq Lst (1 NIL 2 NIL 3))
-> (1 NIL 2 NIL 3)
: (let? A (pop 'Lst) (println 'A A))
A 1
-> 1
: (let? A (pop 'Lst) (println 'A A))
-> NIL
(lieu 'any) -> sym | NIL
any
when it is an external symbol and
currently manifest in heap space, otherwise NIL
. See also ext?
.
: (lieu *DB)
-> {1}
(line 'flg ['cnt ..]) -> lst|sym
flg
is
NIL
, a list of single-character transient symbols is returned. When
cnt
arguments are given, subsequent characters of the input line
are grouped into sublists, to allow parsing of fixed field length records. If
flg
is non-NIL
, strings are returned instead of
single-character lists. NIL
is returned upon end of file. See also
char
, till
and
eof
.
: (line)
abcdefghijkl
-> ("a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l")
: (line T)
abcdefghijkl
-> "abcdefghijkl"
: (line NIL 1 2 3)
abcdefghijkl
-> (("a") ("b" "c") ("d" "e" "f") "g" "h" "i" "j" "k" "l")
: (line T 1 2 3)
abcdefghijkl
-> ("a" "bc" "def" "g" "h" "i" "j" "k" "l")
(lines 'any ..) -> cnt
any
. See also info
.
: (lines "x.l")
-> 11
(link 'any ..) -> any
any
to the end of the list in
the current make
environment. This operation is
efficient also for long lists, because a pointer to the last element of the list
is maintained. link
returns the last linked argument. See also
chain
and made
.
: (make
(println (link 1))
(println (link 2 3)) )
1
3
-> (1 2 3)
(list 'any ..) -> lst
any
arguments.
: (list 1 2 3 4)
-> (1 2 3 4)
: (list 'a (2 3) "Ok")
-> (a (2 3) "Ok")
(lst? 'any) -> flg
T
when the argument any
is a (possibly
empty) list (NIL
or a cons pair cell). See also pair
.
: (lst? NIL)
-> T
: (lst? (1 . 2))
-> T
: (lst? (1 2 3))
-> T
(listen 'cnt1 ['cnt2]) -> cnt | NIL
cnt1
(as received by port
) for an incoming connection, and returns the new
socket descriptor cnt
. While waiting for a connection, a
select
system call is executed for all file descriptors and timers
in the VAL
of the global variable *Run
. If cnt2
is non-NIL
, that
amount of milliseconds is waited maximally, and NIL
is returned
upon timeout. The global variable *Adr
is set to the IP address of
the client. See also accept
, connect
, nagle
and
*Adr
.
: (setq *Socket
(listen (port 6789) 60000) ) # Listen at port 6789 for max 60 seconds
-> 4
: *Adr
-> "127.0.0.1"
(lit 'any) -> any
any
, by
cons
ing it with the quote
function if necessary.
: (lit T)
-> T
: (lit 1)
-> 1
: (lit '(1))
-> (1)
: (lit '(a))
-> '(a)
(load 'any ..) -> any
any
arguments. Normally, the name of each argument is
taken as a file to be executed in a read-eval loop. The argument semantics are
identical to that of in
, with the exception that
if an argument is a symbol and its first character is a hyphen '-', then that
argument is parsed as a function call (without the surrounding parentheses).
When any
is T
, all remaining command line arguments
are loaded recursively. When any
is NIL
, standard
input is read, a prompt is issued before each read operation, the results are
printed to standard output (read-eval-print loop), and load
terminates when an empty line is entered. In any case, load
terminates upon end of file, or when NIL
is read. The hash table
for transient symbols is cleared before and after the load, so that all
transient symbols in the file have a local scope. Returns the value of the last
evaluated expression. See also call
, in
, out
and str
.
: (load "lib.l" "-* 1 2 3")
-> 6
(lock ['sym]) -> cnt | NIL
sym
(file record locking), or
the whole database root file if sym
is NIL
. Returns
NIL
if successful, or the ID of the process currently holding the
lock. When sym
is non-NIL
, the lock is released at the
next top level call to commit
or rollback
, otherwise only when another database is
opened with pool
, or when the process
terminates. See also *Solo
.
: (lock '{1}) # Lock single object
-> NIL
: (lock) # Lock whole database
-> NIL
(-> sym [num]) -> any
sym
at
top level (or level num
) in the current Pilog
environment. See also prove
and unify
.
: (? (append (1 2 3) (4 5 6) @X) (@ println 'X '= (-> @X)))
X = (1 2 3 4 5 6)
@X=(1 2 3 4 5 6)
-> NIL
(loop ['any | (NIL 'any . prg) | (T 'any . prg) ..]) -> any
NIL
or T
as
its CAR
, the clause's second element is evaluated as a condition
and - if the result is NIL
or non-NIL
, respectively -
the prg
is executed and the result returned. See also do
and for
.
: (let N 3
(loop
(prinl N)
(T (=0 (dec 'N)) 'done) ) )
3
2
1
-> done
(low? 'any) -> sym | NIL
any
when the argument is a string (symbol) that starts
with a lowercase character. See also lowc
.
: (low? "a")
-> "a"
: (low? "A")
-> NIL
: (low? 123)
-> NIL
: (low? ".")
-> NIL
(lowc 'any) -> any
any
is not a symbol, it is returned
as it is. Otherwise, a new transient symbol with all characters of
any
, converted to lower case, is returned. See also uppc
, fold
and low?
.
: (lowc 123)
-> 123
: (lowc "ABC")
-> "abc"
(lt0 'any) -> num | NIL
num
when the argument is a number and less than zero,
otherwise NIL
. See also ge0
,
gt0
, =0
and
n0
.
: (lt0 -2)
-> -2
: (lt0 3)
-> NIL
(lup 'lst 'any) -> lst
(lup 'lst 'any 'any2) -> lst
any
in the CAR-elements of cells stored in the index
tree lst
, as built up by idx
. In
the first form, the first found cell is returned, in the second form a list of
all cells whose CAR is in the range any
.. any2
. See
also assoc
.
: (idx 'A 'a T)
-> NIL
: (idx 'A (1 . b) T)
-> NIL
: (idx 'A 123 T)
-> NIL
: (idx 'A (1 . a) T)
-> NIL
: (idx 'A (1 . c) T)
-> NIL
: (idx 'A (2 . d) T)
-> NIL
: (idx 'A)
-> (123 a (1 . a) (1 . b) (1 . c) (2 . d))
: (lup A 1)
-> (1 . b)
: (lup A 2)
-> (2 . d)
: (lup A 1 1)
-> ((1 . a) (1 . b) (1 . c))
: (lup A 1 2)
-> ((1 . a) (1 . b) (1 . c) (2 . d))
(made ['lst1 ['lst2]]) -> lst
make
environment. All list elements already produced
with chain
and link
are discarded, and lst1
is used
instead. Optionally, lst2
can be specified as the new linkage cell,
otherwise the last cell of lst1
is used. When called without
arguments, made
does not modify the environment. In any case, the
current list is returned.
: (make
(link 'a 'b 'c) # Link three items
(println (made)) # Print current list (a b c)
(made (1 2 3)) # Discard it, start new with (1 2 3)
(link 4) ) # Link 4
(a b c)
-> (1 2 3 4)
(make .. [(made 'lst ..)] .. [(link 'any ..)] ..) -> any
made
, chain
and
link
functions, and returns the result list.
For efficiency, pointers to the head and the tail of the list are maintained
internally.
: (make (link 1) (link 2 3) (link 4))
-> (1 2 3 4)
: (make (made (1 2 3)) (link 4))
-> (1 2 3 4)
(map 'fun 'lst ..) -> lst
fun
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to fun
in the same way. Returns the result of the last
application.
: (map println (1 2 3 4) '(A B C))
(1 2 3 4) (A B C)
(2 3 4) (B C)
(3 4) (C)
(4) NIL
-> NIL
(mapc 'fun 'lst ..) -> any
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns the result of the last application.
: (mapc println (1 2 3 4) '(A B C))
1 A
2 B
3 C
4 NIL
-> NIL
(mapcan 'fun 'lst ..) -> lst
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns a (destructively) concatenated list of all results.
: (mapcan reverse '((a b c) (d e f) (g h i)))
-> (c b a f e d i h g)
(mapcar 'fun 'lst ..) -> lst
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns a list of all results.
: (mapcar + (1 2 3) (4 5 6))
-> (5 7 9)
: (mapcar '((X Y) (+ X (* Y Y))) (1 2 3 4) (5 6 7 8))
-> (26 38 52 68)
(mapcon 'fun 'lst ..) -> lst
fun
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to fun
in the same way. Returns a (destructively)
concatenated list of all results.
: (mapcon copy '(1 2 3 4 5))
-> (1 2 3 4 5 2 3 4 5 3 4 5 4 5 5)
(maplist 'fun 'lst ..) -> lst
fun
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to fun
in the same way. Returns a list of all results.
: (maplist cons (1 2 3) '(A B C))
-> (((1 2 3) A B C) ((2 3) B C) ((3) C))
(maps 'fun 'sym ['lst ..]) -> any
fun
to all properties of sym
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns the result of the last application. See also
putl
and getl
.
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (put 'X 'flg T)
-> T
: (getl 'X)
-> (flg (2 . b) (1 . a))
: (maps println 'X '(A B))
flg A
(2 . b) B
(1 . a) NIL
-> NIL
(mark 'sym|0 [NIL | T | 0]) -> flg
sym
in the database (for a
second argument of NIL
, T
or 0
,
respectively), and returns the old value. The marks are local to the current
process (not stored in the database), and vanish when the process terminates. If
the first argument is zero, all marks are cleared.
: (pool "db")
-> T
: (mark '{1} T) # Mark
-> NIL
: (mark '{1}) # Test
-> T # -> marked
: (mark '{1} 0) # Unmark
-> T
: (mark '{1}) # Test
-> NIL # -> unmarked
(match 'lst1 'lst2) -> flg
lst1
as a pattern to be matched against
lst2
, and returns T
when successful. Atoms must be
equal, and sublists must match recursively. Symbols in the pattern list with
names starting with an at-mark "@
" (see pat?
) are taken as wildcards. They can match zero, one
or more elements, and are bound to the corresponding data. See also chop
, split
and
fill
.
: (match '(@A is @B) '(This is a test))
-> T
: @A
-> (This)
: @B
-> (a test)
: (match '(@X (d @Y) @Z) '((a b c) (d (e f) g) h i))
-> T
: @X
-> ((a b c))
: @Y
-> ((e f) g)
: @Z
-> (h i)
(max 'any ..) -> any
any
arguments. See also Comparing.
: (max 2 'a 'z 9)
-> z
: (max (5) (2 3) 'X)
-> (5)
(maxi 'fun 'lst ..) -> any
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns that element from lst
for that
fun
returned a maximal value. See also mini
.
: (setq A 1 B 2 C 3)
-> 3
: (maxi val '(A B C))
-> C
: (maxi # Symbol with largest list value
'((X)
(and (pair (val X)) (size @)) )
(what) )
-> *History
(member 'any 'lst) -> any
lst
that starts with any
when
any
is a member of lst
, otherwise NIL
.
See also memq
, assoc
and idx
.
: (member 3 (1 2 3 4 5 6))
-> (3 4 5 6)
: (member 9 (1 2 3 4 5 6))
-> NIL
: (member '(d e f) '((a b c) (d e f) (g h i)))
-> ((d e f) (g h i))
(memq 'any 'lst) -> any
lst
that starts with any
when
any
is a member of lst
, otherwise NIL
.
==
is used for comparison (pointer equality). See
also member
, mmeq
, asoq
and delq
.
: (memq 'c '(a b c d e f))
-> (c d e f)
: (memq 3 (1 2 3 4 5 6))
-> NIL
(meta 'obj|typ 'sym ['sym2|cnt ..]) -> any
any
, by searching the property lists
of the classes and superclasses of obj
, or the classes in
typ
, for the property key sym
, and by applying the
get
algorithm to the following optional
arguments.
: (setq A '(B)) # Be 'A' an object of class 'B'
-> (B)
: (put 'B 'a 123)
-> 123
: (meta 'A 'a) # Fetch 'a' from 'B'
-> 123
(meth 'obj ..) -> any
dm
as a template to initialize the VAL
of message symbols. It searches
for itself in the methods of obj
and its classes and superclasses,
and executes that method. An error "Bad message"
is issued if the
search is unsuccessful.
: meth
-> 67283504 # Value of 'meth'
: stop>
-> 67283504 # Value of any message
(method 'msg 'obj) -> fun
msg
to the object obj
. If the message
cannot be located in obj
, its classes and superclasses,
NIL
is returned. See also send
and
try
.
: (method 'mis> '+Number)
-> ((Val Obj) (and Val (not (num? Val)) "Numeric input expected"))
(min 'any ..) -> any
any
arguments. See also Comparing.
: (min 2 'a 'z 9)
-> 2
: (min (5) (2 3) 'X)
-> X
(mini 'fun 'lst ..) -> any
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns that element from lst
for that
fun
returned a minimal value. See also maxi
.
: (setq A 1 B 2 C 3)
-> 3
: (mini val '(A B C))
-> A
(mix 'lst cnt|'any ..) -> lst
lst
, as
specified by the following cnt|'any
arguments. If such an argument
is a number, the cnt
'th element from lst
is taken,
otherwise that arguments is evaluated and the result is used.
: (mix '(a b c d) 3 4 1 2)
-> (c d a b)
: (mix '(a b c d) 1 'A 4 'D)
-> (a A d D)
(mmeq 'lst 'lst) -> any
lst
that starts with a
member of the first argument lst
, otherwise NIL
.
==
is used for comparison (pointer equality). See
also member
, memq
, asoq
and delq
.
: (mmeq '(a b c) '(d e f))
-> NIL
: (mmeq '(a b c) '(d b x))
-> (b x)
(n== 'any ..) -> flg
T
when not all any
arguments are the same
(pointer equality). (n== 'any ..)
is equivalent to (not (==
'any ..))
. See also ==
.
: (n== 'a 'a)
-> NIL
: (n== 1 1)
-> T
(n0 'any) -> flg
T
when any
is not a number with value
zero. See also =0
, lt0
, ge0
and gt0
.
: (n0 (- 6 3 2 1))
-> NIL
: (n0 'a)
-> T
(nT 'any) -> flg
T
when any
is not the symbol
T
. See also =T.
: (nT 0)
-> T
: (nT "T")
-> T
: (nT T)
-> NIL
(nagle 'cnt 'flg) -> cnt
cnt
if
flg
is NIL
, or enables it if flg
is
non-NIL
. Returns the socket descriptor. See also listen
and connect
.
: (nagle (connect "localhost" 8080) NIL) # Disable the nagle algorithm
-> 3
(name 'sym ['sym2]) -> sym
sym2
is not given, a new transient symbol with the
name of sym
. Otherwise sym
must be a transient symbol,
and its name is changed to that of sym2
. See also str
, sym
, zap
and intern
.
: (name 'abc)
-> "abc"
: (name "abc")
-> "abc"
: (name '{abc})
-> "abc"
: (name (new))
-> NIL
: (de foo (Lst) (car Lst)) # 'foo' calls 'car'
-> foo
: (intern (name (zap 'car) "xxx")) # Globally change the name of 'car'
-> xxx
: (xxx (1 2 3))
-> 1
: (pp 'foo)
(de foo (Lst)
(xxx Lst) ) # Name changed
-> foo
: (foo (1 2 3)) # 'foo' still works
-> 1
: (car (1 2 3)) # Reader returns a new 'car' symbol
!? (car (1 2 3))
car -- Undefined
?
(nand 'any ..) -> flg
any
are evaluated from left to
right. If NIL
is encountered, T
is returned
immediately. Else NIL
is returned. (nand ..)
is
equivalent to (not (and ..))
.
: (nand (lt0 7) (read))
-> T
: (nand (lt0 -7) (read))
abc
-> NIL
: (nand (lt0 -7) (read))
NIL
-> T
(need 'cnt ['lst ['any]]) -> lst
cnt
elements. When called without
optional arguments, a list of cnt
NIL
's is returned.
When lst
is given, it is extended to the left (if cnt
is positive) or (destructively) to the right (if cnt
is negative)
with any
elements.
: (need 5)
-> (NIL NIL NIL NIL NIL) # Allocate 5 cells
: (need 5 '(a b c))
-> (NIL NIL a b c)
: (need -5 '(a b c))
-> (a b c NIL NIL)
: (need 5 '(a b c) " ") # String alignment
-> (" " " " a b c)
(new ['flg|num] ['typ ['any ..]]) -> sym
flg
is given and
non-NIL
, the new object will be an external symbol (created in the
corresponding database file if num
is given). typ
(typically a list of classes) is assigned to the VAL
, and the
initial T
message is sent with the arguments any
to
the new object. See also box
.
: (new)
-> $134426427
: (new T '(+Address))
-> {1A;3}
(next) -> any
@
). Returns the next argument from the internal list. See also
args
, arg
,
rest
, and pass
.
: (de foo @ (println (next))) # Print next argument
-> foo
: (foo)
NIL
-> NIL
: (foo 123)
123
-> 123
(nil . prg) -> NIL
prg
, and returns NIL
. See also t
, prog
, prog1
and prog2
.
: (nil (println 'Ok))
Ok
-> NIL
(nond (('any1 . prg1) ('any2 . prg2) ..)) -> any
anyN
conditions evaluates to NIL
, prgN
is executed and the
result returned. Otherwise (all conditions evaluate to non-NIL
),
NIL
is returned. See also cond
,
ifn
and unless
.
: (nond
((= 3 3) (println 1))
((= 3 4) (println 2))
(NIL (println 3)) )
2
-> 2
(nor 'any ..) -> flg
any
are evaluated from left to
right. If a non-NIL
value is encountered, NIL
is
returned immediately. Else T
is returned. (nor ..)
is
equivalent to (not (or ..))
.
: (nor (lt0 7) (= 3 4))
-> T
(not 'any) -> flg
T
if any
evaluates to
NIL
.
: (not (== 'a 'a))
-> NIL
: (not (get 'a 'a))
-> T
(nth 'lst 'cnt ..) -> lst
lst
starting from the cnt
'th
element of lst
. Successive cnt
arguments operate on
the results in the same way. (nth 'lst 2)
is equivalent to
(cdr 'lst)
.
: (nth '(a b c d) 2)
-> (b c d)
: (nth '(a (b c) d) 2 2)
-> (c)
: (cdadr '(a (b c) d))
-> (c)
(num? 'any) -> num | NIL
any
when the argument any
is a number,
otherwise NIL
.
: (num? 123)
-> 123
: (num? (1 2 3))
-> NIL
(off sym ..) -> NIL
NIL
in the VAL
's of all argument symbols
sym
. See also on
, onOff
, zero
and
one
.
: (off A B)
-> NIL
: A
-> NIL
: B
-> NIL
(offset 'lst1 'lst2) -> cnt | NIL
cnt
position of the tail list lst1
in
lst2
, or NIL
if it is not found. See also index
.
: (offset '(c d e f) '(a b c d e f))
-> 3
: (offset '(c d e) '(a b c d e f))
-> NIL
(on sym ..) -> T
T
in the VAL
's of all argument symbols
sym
. See also off
, onOff
, zero
and
one
.
: (on A B)
-> T
: A
-> T
: B
-> T
(one sym ..) -> 1
1
in the VAL
's of all argument symbols
sym
. See also zero
, on
, off
and onOff
.
: (one A B)
-> 1
: A
-> 1
: B
-> 1
(onOff sym ..) -> flg
VAL
's of all argument symbols
sym
. Returns the new value of the last symbol. See also on
, off
, zero
and one
.
: (onOff A B)
-> T
: A
-> T
: B
-> T
: (onOff A B)
-> NIL
: A
-> NIL
: B
-> NIL
(open 'sym) -> cnt | NIL
sym
in read/write mode, and returns a file
descriptor cnt
(or NIL
on error). If the file does not
exist, it is created. The file descriptor can be used in subsequent calls to
in
and out
. See
also close
.
: (open "x")
-> 3
(opt) -> sym
Invocation
and argv
.
$ ./p -"de f () (println 'opt (opt))" -f abc -bye
opt "abc"
(or 'any ..) -> any
any
are evaluated from left to
right. If a non-NIL
value is encountered, it is returned
immediately. Else the result of the last expression is returned.
: (or (= 3 3) (read))
-> T
: (or (= 3 4) (read))
abc
-> abc
(out 'any . prg) -> any
any
as output channel during the execution of
prg
. The current output channel will be saved and restored
appropriately. If the argument is NIL
, standard output is used. If
the argument is a symbol, it is used as a file name (opened in "append" mode if
the first character is "+
"). If it is a number, it is used as the
descriptor of an open file. Otherwise (if it is a list), it is taken as a
command with arguments, and a pipe is opened for output. See also call
, in
, pipe
, ctl
and load
.
: (out "a" (println 123 '(a b c) 'def)) # Write one line to file "a"
-> def
(pack 'any ..) -> sym
any
. A NIL
arguments contributes nothing to the result
string, a number is converted to a digit string, a symbol supplies the
characters of its name, and for a list its elements are taken. See also text
and glue
.
: (pack 'car " is " 1 '(" symbol " name))
-> "car is 1 symbol name"
(pair 'any) -> any
any
when the argument a cons pair cell. See also
atom
.
: (pair NIL)
-> NIL
: (pair (1 . 2))
-> (1 . 2)
: (pair (1 2 3))
-> (1 2 3)
(pass 'fun ['any ..]) -> any
fun
all arguments any
, and all remaining
variable arguments (@
) as they would be returned by rest
. (pass 'fun 'any)
is equivalent to
(apply 'fun (cons 'any (rest)))
. See also apply
.
: (de bar (A B . @)
(println 'bar A B (rest)) )
-> bar
: (de foo (A B . @)
(println 'foo A B)
(pass bar 1)
(pass bar 2) )
-> foo
: (foo 'a 'b 'c 'd 'e 'f)
foo a b
bar 1 c (d e f)
bar 2 c (d e f)
-> (d e f)
(path 'sym) -> sym
@
" character in the sym
argument with the Pico Lisp Home Directory, as it was remembered during
interpreter startup. Optionally, the name may be preceded by a "+
"
character (as used by out
). This mechanism is
used internally by all I/O functions. See also Invocation
.
$ /usr/bin/picolisp /usr/lib/picolisp/lib.l
: (path "a/b/c")
-> "a/b/c"
: (path "@a/b/c")
-> "/usr/lib/picolisp/a/b/c"
: (path "+@a/b/c")
-> "+/usr/lib/picolisp/a/b/c"
(pat? 'any) -> sym | NIL
any
when the argument any
is a symbol
whose name starts with an at-mark "@
", otherwise NIL
.
: (pat? '@)
-> @
: (pat? "@Abc")
-> "@Abc"
: (pat? "ABC")
-> NIL
: (pat? 123)
-> NIL
(peek) -> sym
char
would return. See also skip
.
$ cat a
# Comment
abcd
$ ./p dbg.l
: (in "a" (list (peek) (char)))
-> ("#" "#")
(pick 'fun 'lst ..) -> any
fun
to successive elements of lst
until
non-NIL
is returned. Returns that value, or NIL
if
fun
did not return non-NIL
for any element of
lst
. When additional lst
arguments are given, their
elements are also passed to fun
. See also seek
, find
.
: (put 'D 'str "Hello")
-> "Hello"
: (pick '((X) (get X 'str)) '(A B C D E F))
-> "Hello"
(pipe exe) -> cnt
(pipe exe . prg) -> any
exe
in a fork
'ed
child process (which terminates thereafter). In the first form,
pipe
just returns a file descriptor to read from the standard
output of that process. In the second form, it opens the standard output of that
process as input channel during the execution of prg
. The current
input channel will be saved and restored appropriately. See also in
and out
.
: (pipe # equivalent to 'any'
(prinl "(a b # Comment^Jc d)") # (child process)
(read) ) # (parent process)
-> (a b c d)
: (pipe # pipe through an external program
(out '(tr "[a-z]" "[A-Z]") # (child process)
(prinl "abc def ghi") )
(line T) ) # (parent process)
-> "ABC DEF GHI"
(poll 'cnt) -> flg
cnt
. See also open
, in
and close
.
: (and (poll *Fd) (in *Fd (read))) # Prevent blocking
(pool ['sym1 ['lst] ['sym2]]) -> flg
sym1
as a database file in read/write mode. If
the file does not exist, it is created. A currently open database is closed.
lst
is a list of block size scale factors (i.e. numbers),
defaulting to (2) (for a single file with a 256 byte block size). If
lst
is given, an individual database file is opened for each item.
If sym2
is non-NIL
, it is opened in append-mode as a
journal file. Returns T
when successful. See also journal
.
: (pool "/dev/hda2")
-> T
(pop 'var) -> any
CAR
) from the stack in
var
. See also push
, queue
, cut
, del
and fifo
.
: (setq S '((a b c) (1 2 3)))
-> ((a b c) (1 2 3))
: (pop S)
-> a
: (pop (cdr S))
-> 1
: (pop 'S)
-> (b c)
: S
-> ((2 3))
(port ['T] 'cnt|(cnt . cnt) ['var]) -> cnt
cnt
(or a UDP-Port if the first argument is
T
), and returns a socket descriptor suitable as an argument for
listen
or accept
(or udp
,
respectively). If cnt
is zero, some free port number is allocated.
If a pair of cnt
s is given instead, it should be a range of numbers
which are tried in turn. When var
is given, it is bound to the port
number.
: (port 0 'A) # Allocate free port
-> 4
: A
-> 1034 # Got 1034
: (port (4000 . 4008) 'A) # Try one of these ports
-> 5
: A
-> 4002
(pr 'any ..) -> any
any
arguments to the current output
channel in encoded binary format. See also rd
,
wr
and rpc
.
: (out "x" (pr 7 "abc" (1 2 3) 'a)) # Print to "x"
-> a
: (hd "x")
00000000 04 0E 0E 61 62 63 01 04 02 04 04 04 06 03 05 61 ...abc.........a
-> NIL
(pre? 'sym1 'sym2) -> flg
NIL
when the name of the first symbol
sym1
is a prefix string of the name of the second symbol
sym2
. See also sub?
.
: (pre? "abc" "abcdef")
-> T
: (pre? "def" "abcdef")
-> NIL
: (pre? "" "abcdef")
-> T
(prin 'any ..) -> any
any
arguments to the
current output channel. No space or newline is printed between individual items,
of after the last item. For lists, all elements are prin
'ted
recursively. See also prinl
.
: (prin 'abc 123 '(a 1 b 2))
abc123a1b2-> (a 1 b 2)
(prinl 'any ..) -> any
any
arguments to the
current output channel, followed by a newline. No space or newline is printed
between individual items. For lists, all elements are prin
'ted
recursively. See also prin
.
: (prinl 'abc 123 '(a 1 b 2))
abc123a1b2
-> (a 1 b 2)
(print 'any ..) -> any
any
arguments to the current output channel. If
there is more than one argument, a space is printed between successive
arguments. No space or newline is printed after the last item. See also println
, printsp
,
sym
and str
: (print 123)
123-> 123
: (print 1 2 3)
1 2 3-> 3
: (print '(a b c) 'def)
(a b c) def-> def
(println 'any ..) -> any
any
arguments to the current output channel,
followed by a newline. If there is more than one argument, a space is printed
between successive arguments. See also print
,
printsp
.
: (println '(a b c) 'def)
(a b c) def
-> def
(printsp 'any ..) -> any
any
arguments to the current output channel,
followed by a space. If there is more than one argument, a space is printed
between successive arguments. See also print
,
println
.
: (printsp '(a b c) 'def)
(a b c) def -> def
(prog . prg) -> any
prg
, and returns the result of the last expression.
See also nil
, t
,
prog1
and prog2
.
: (prog (print 1) (print 2) (print 3))
123-> 3
(prog1 'any1 . prg) -> any1
any1
. See also nil
, t
, prog
and prog2
.
: (prog1 (print 1) (print 2) (print 3))
123-> 1
(prog2 'any1 'any2 . prg) -> any2
any2
. See also nil
, t
, prog
and prog1
.
: (prog2 (print 1) (print 2) (print 3))
123-> 2
(prop 'sym1|lst ['sym2|cnt ..] 'sym) -> lst|sym
sym
from a symbol. That
symbol is sym1
(if no other arguments are given), or a symbol found
by applying the get
algorithm to
sym1|lst
and the following arguments. The property (the cell, not
just its value) is returned, suitable for direct (destructive) manipulations.
: (put 'X 'cnt 0)
-> 0
: (prop 'X 'cnt)
-> (0 . cnt)
: (inc (prop 'X 'cnt)) # Directly manipulate the property value
-> 1
: (get 'X 'cnt)
-> 1
(protect . prg) -> any
prg
, and returns the result of the last expression. If
a SIGTERM signal is received during that time, termination of the process will
be delayed until the execution of prg
is completed. See also
kill
.
: (protect (journal "db1.log" "db2.log"))
-> T
(prove 'lst ['lst]) -> lst
NIL
if not successful. The query list is modified as a side effect,
allowing subsequent calls to prove
for further results. The
optional second argument may contain a list of symbols; in that case the
successful matches of rules defined for these symbols will be traced. See also
goal
, ->
and unify
.
: (prove (goal '((equal 3 3))))
-> T
: (prove (goal '((equal 3 @X))))
-> ((@X . 3))
: (prove (goal '((equal 3 4))))
-> NIL
(push 'var 'any ..) -> any
var
. The any
arguments are cons'ed in front of the value list. See also push1
, pop
, queue
and fifo
.
: (push 'S 3) # Use the VAL of 'S' as a stack
-> 3
: S
-> (3)
: (push 'S 2)
-> 2
: (push 'S 1)
-> 1
: S
-> (1 2 3)
: (push S 999) # Now use the CAR of the list in 'S'
-> 999
: (push S 888 777)
-> 777
: S
-> ((777 888 999 . 1) 2 3)
(push1 'var 'any ..) -> any
var
. Each any
argument
is cons'ed in front of the value list only if it is not already a member
of that list. See also push
, pop
and queue
.
: (push1 'S 1 2 3)
-> 3
: S
-> (3 2 1)
: (push1 'S 2 4)
-> 4
: S
-> (4 3 2 1)
(put 'sym1|lst ['sym2|cnt ..] 'sym 'any) -> any
any
for a property key sym
in a
symbol. That symbol is sym1
(if no other arguments are given), or a
symbol found by applying the get
algorithm to
sym1|lst
and the following arguments.
: (put 'X 'a 1)
-> 1
: (get 'X 'a)
-> 1
: (prop 'X 'a)
-> (1 . a)
(putl 'sym1|lst1 ['sym2|cnt ..] 'lst) -> lst
lst
in a symbol. That
symbol is sym1
(if no other arguments are given), or a symbol found
by applying the get
algorithm to
sym1|lst1
and the following arguments. All previously defined
properties for that symbol are lost. See also getl
and maps
.
: (putl 'X '((123 . a) flg ("Hello" . b)))
-> ((123 . a) flg ("Hello" . b))
: (get 'X 'a)
-> 123
: (get 'X 'b)
-> "Hello"
: (get 'X 'flg)
-> T
(pwd) -> sym
dir
and cd
.
: (pwd)
-> "/home/app/"
(quote . any) -> any
any
unevaluated. The reader recognizes the single quote
char '
as a macro for this function. See also lit
.
: 'a
-> a
: '(foo a b c)
-> (foo a b c)
: (quote (quote (quote a)))
-> ('('(a)))
(queue 'var 'any) -> any
var
. The any
argument is (destructively) concatenated to the end of the value list. See also
push
, pop
and
fifo
.
: (queue 'A 1)
-> 1
: (queue 'A 2)
-> 2
: (queue 'A 3)
-> 3
: A
-> (1 2 3)
: (pop 'A)
-> 1
: A
-> (2 3)
(quit ['any ['any]])
finally
expressions are executed and control is
returned to the top level read-eval-print loop. Otherwise, an error handler is
entered. The first argument can be some error message, and the second might be
the reason for the error. See also Error
Handling
.
: (de foo (X) (quit "Sorry, my error" X))
-> foo
: (foo 123) # 'X' is bound to '123'
123 -- Sorry, my error # Error entered
? X # Inspect 'X'
-> 123
? # Empty line: Exit
:
(rand ['cnt1 'cnt2] | ['T]) -> cnt | flg
T
, a
boolean value flg
is returned. See also seed
.
: (rand 3 9)
-> 3
: (rand 3 9)
-> 7
(rank 'any 'lst ['flg]) -> lst
lst
should be sorted. Returns the
element from lst
with a maximal CAR
less or equal to
any
(if flg
is NIL
), or with a minimal
CAR
greater or equal to any
(if flg
is
non-NIL
), or NIL
if no match is found. See also Comparing.
: (rank 0 '((1 . a) (100 . b) (1000 . c)))
-> NIL
: (rank 50 '((1 . a) (100 . b) (1000 . c)))
-> (1 . a)
: (rank 100 '((1 . a) (100 . b) (1000 . c)))
-> (100 . b)
: (rank 300 '((1 . a) (100 . b) (1000 . c)))
-> (100 . b)
: (rank 9999 '((1 . a) (100 . b) (1000 . c)))
-> (1000 . c)
: (rank 50 '((1000 . a) (100 . b) (1 . c)) T)
-> (100 . b)
(raw ['flg]) -> flg
NIL
for "cooked mode"). Otherwise, the
console is set to the new state. See also key
.
$ ./p
: (raw)
-> NIL
$ ./p dbg.l
: (raw)
-> T
(rd ['sym]) -> any
(rd 'cnt) -> num | NIL
cnt
argument (second form), that number
of raw bytes (in big endian format if cnt
is positive) is read as a
single number. Upon end of file, if the sym
argument is given, it
is returned, otherwise NIL
. See also pr
and wr
.
: (out "x" (pr 'abc "EOF" 123 "def"))
-> "def"
: (in "x" (rd))
-> abc
: (in "x"
(make
(use X
(until (== "EOF" (setq X (rd "EOF"))) # '==' detects end of file
(link X) ) ) ) )
-> (abc "EOF" 123 "def") # as opposed to reading a symbol "EOF"
: (in "/dev/urandom" (rd 20))
-> 396737673456823753584720194864200246115286686486
(read ['sym1 ['sym2]]) -> any
NIL
is returned
upon end of file. When called without arguments, an arbitrary Lisp expression is
read. Otherwise, a token (a number, or an internal or transient symbol) is read.
In that case, sym1
specifies which set of characters to accept for
internal symbols (in addition to the standard alphanumerical characters), and
sym2
an optional comment character. See also any
, str
, skip
and eof
.
: (list (read) (read) (read)) # Read three things from console
123 # a number
abcd # a symbol
(def # and a list
ghi
jkl
)
-> (123 abcd (def ghi jkl))
: (make (while (read "_" "#") (link @)))
abc = def_ghi("xyz"+-123) # Comment
""
-> (abc "=" def_ghi "(" "xyz" "+" -123 ")")
(rel sym lst [any ..]) -> any
sym
for the current class
*Class
, using lst
as the list of classes for that
relation, and possibly additional arguments any
for its
initialization.
(class +Person +Entity)
(rel nm (+List +Ref +String)) # Names
(rel tel (+Ref +String)) # Telephone
(rel adr (+Joint) prs (+Address)) # Address
(class +Address +Entity)
(rel Cit (+Need +Hook +Link) (+City)) # City
(rel str (+List +Ref +String) Cit) # Street
(rel prs (+List +Joint) adr (+Person)) # Inhabitants
(class +City +Entity)
(rel nm (+List +Ref +String)) # Zip / Names
(replace 'lst 'any1 'any2 ..) -> lst
lst
all occurrences of any1
with
any2
. For optional additional argument pairs, this process is
repeated.
: (replace '(a b b a) 'a 'A)
-> (A b b A)
: (replace '(a b b a) 'b 'B)
-> (a B B a)
: (replace '(a b b a) 'a 'B 'b 'A)
-> (B A A B)
(rest) -> lst
@
). Returns the the list of all remaining arguments from the
internal list. See also args
, next
, arg
and pass
.
: (de foo @ (println (rest)))
-> foo
: (foo 1 2 3)
(1 2 3)
-> (1 2 3)
(reverse 'lst) -> lst
lst
. See also flip
.
: (reverse (1 2 3 4))
-> (4 3 2 1)
(rewind) -> flg
T
when successful. See also flush
.
(rollback) -> flg
begin
are discarded. Returns T
when the
topmost transaction is cancelled. See also commit
.
: (pool "db")
-> T
: (begin)
-> T
: (rollback) # Rollback second level
-> NIL
: (rollback) # Rollback top level
-> T
(rot 'lst ['cnt]) -> lst
lst
are (destructively)
shifted right, and the value from the last cell is stored in the first cell.
Without the optional cnt
argument, the whole list is rotated.
Otherwise only the first cnt
elements are rotated.
: (rot (1 2 3 4)) # Rotate all four elements
-> (4 1 2 3)
: (rot (1 2 3 4 5 6) 3) # Rotate only the first three elements
-> (3 1 2 4 5 6)
(rpc 'sym ['any ..]) -> flg
(sym any ..)
via standard output in encoded binary format. See also
pr
, pipe
,
tell
and hear
.
: (hear (pipe (do 3 (wait 2000) (rpc 'println ''Ok))))
-> 3
: Ok # every two seconds
Ok
Ok
(run 'any ['cnt]) -> any
any
is an atom, run
behaves like
eval
. Otherwise any
is a list, which is evaluated in
sequence. The last result is returned. If a binding environment offset
cnt
is given, that evaluation takes place in the corresponding
environment. See also eval
and up
.
: (run '((println (+ 1 2 3)) (println 'Ok)))
6
Ok
-> Ok
(sect 'lst 'lst) -> lst
lst
arguments. See also
diff
.
: (sect (1 2 3 4) (3 4 5 6))
-> (3 4)
: (sect (1 2 3) (4 5 6))
-> NIL
(seed 'any) -> cnt
rand
.
: (seed "init string")
-> 2015582081
: (rand)
-> -706917003
: (rand)
-> 1224196082
: (seed "init string")
-> 2015582081
: (rand)
-> -706917003
: (rand)
-> 1224196082
(seek 'fun 'lst ..) -> lst
fun
to lst
and all successive
CDR
's, until non-NIL
is returned. Returns the tail of
lst
starting with that element, or NIL
if
fun
did not return non-NIL
for any element of
lst
. When additional lst
arguments are given, they are
passed to fun
in the same way. See also find
, pick
.
: (seek '((X) (> (car X) 9)) (1 5 8 12 19 22))
-> (12 19 22)
(send 'msg 'obj ['any ..]) -> any
msg
to the object obj
,
optionally with arguments any
. If the message cannot be located in
obj
, its classes and superclasses, an error "Bad
message"
is issued. See also try
and
method
.
: (send 'stop> Dlg) # Equivalent to (stop> Dlg)
-> NIL
(seq 'cnt|sym1 ['sym2 ['num]]) -> sym | num | NIL
cnt
'th database file, or the next external symbol following
sym1
in the database, or NIL
when the end of the
database is reached. When sym2
is given, the database is extended
up to (including the creation of) sym2
. If num
is
given, it should be the return value of a previous call to seq
, and
is used as an internal free list link. See also free
.
: (pool "db")
-> T
: (seq *DB)
-> {2}
: (seq @)
-> {3}
(set 'var 'any ..) -> any
any
in the var
arguments.
: (set 'L '(a b c) (cdr L) '999)
-> 999
: L
-> (a 999 c)
(setq var 'any ..) -> any
any
in the var
arguments.
: (setq A 123 B (list A A)) # Set 'A' to 123, then 'B' to (123 123)
-> (123 123)
(size 'any) -> cnt
any
. For numbers this is the number of
bytes needed for the value, for external symbols it is the number of bytes it
would occupy in the database, for other symbols it is the number of bytes
occupied in the UTF-8 representation of the name, and for lists it is the total
number of cells in this list and all its sublists. See also length
.
: (size "abc")
-> 3
: (size "äbc")
-> 4
: (size 123)
-> 1
: (size (1 (2) 3))
-> 4
(skip ['sym]) -> sym
sym
is given) in the
input stream. Returns the next available character, or NIL
upon end
of file. See also peek
and eof
.
$ cat a
# Comment
abcd
$ ./p dbg.l
: (in "a" (skip "#"))
-> "a"
(sort 'lst) -> lst
lst
by destructively exchanging its elements. See also Comparing.
: (sort '(a 3 1 (1 2 3) d b 4 T NIL (a b c) (x y z) c 2))
-> (NIL 1 2 3 4 a b c d (1 2 3) (a b c) (x y z) T)
(space ['cnt]) -> cnt
cnt
spaces, or a single space when cnt
is
not given.
: (space)
-> T
: (space 1)
-> T
: (space 2)
-> T
(sp? 'any) -> flg
T
when the argument any
is
NIL
, or if it is a string (symbol) that consists only of whitespace
characters.
: (sp? " ")
-> T
: (sp? "ABC")
-> NIL
: (sp? 123)
-> NIL
(split 'lst 'any ..) -> lst
lst
at all places containing an element any
and returns the resulting list of sublists.
: (split (1 a 2 b 3 c 4 d 5 e 6) 'e 3 'a)
-> ((1) (2 b) (c 4 d 5) (6))
: (mapcar pack (split (chop "The quick brown fox") " "))
-> ("The" "quick" "brown" "fox")
(sqrt 'num) -> num
num
argument.
: (sqrt 64)
-> 8
: (sqrt 1000)
-> 31
: (sqrt 10000000000000000000000000000000000000000)
-> 100000000000000000000
(state 'var ((sym|lst sym [. prg]) . prg) ..) -> any
var
holds the
current state as a symbolic value. When a clause is found that contains the
current state in its CAAR sym|lst
value, and either has no
prg
condition in its CDDAR, or that condition returns
non-NIL
, the current state will be set to the CADAR
sym
of the clause, the body prg
in its CDR will be
executed, and the result returned. T
is a catch-all for any state.
If no state-condition matches, NIL
is returned. See also case
and job
.
: (de tst ()
(job '((Cnt . 4))
(state '(start)
((start run) (printsp 'start))
((run run (gt0 (dec 'Cnt)))
(printsp 'run) )
((run stop) (printsp 'run))
((stop start) (setq Cnt 4) (println 'stop)) ) ) )
-> tst
: (do 12 (tst))
start run run run run stop
start run run run run stop
-> stop
: (pp 'tst)
(de tst NIL
(job '((Cnt . 4))
(state '(start)
...
-> tst
: (do 3 (tst))
start run run -> run
: (pp 'tst)
(de tst NIL
(job '((Cnt . 2))
(state '(run)
...
-> tst
(stem 'lst 'any ..) -> lst
lst
that does not contain any of the
any
arguments. (stem 'lst 'any ..)
is equivalent to
(last (split 'lst 'any ..))
. See also tail
and split
.
: (stem (chop "abc/def\\ghi") "/" "\\")
-> ("g" "h" "i")
(stk any ..) -> T
any
arguments are printed as a header, then each stack entry is
printed per line, preceded by its (hexadecimal) address. See also env
.
: (cons 'A (stk Test))
(Test)
BFFFF69C A
BFFFF70C (cons 'A (stk Test))
-> (A . T)
(stamp ['dat 'tim]) -> sym
dat
and/or tim
is missing, the current date or time is
used. See also date
and time
.
: (stamp)
-> "2000-09-12 07:48:04"
: (stamp (date) 0)
-> "2000-09-12 00:00:00"
: (stamp (date 2000 1 1) (time 12 0 0))
-> "2000-01-01 12:00:00"
(stat) -> num
heap
.
: (stat)
1 7%
-> 66892
(str 'sym) -> lst
(str 'lst) -> sym
sym
is parsed into a list. This
mechanism is also used by load
. The second form
does the reverse operation by building a string from a list. See also any
, name
and sym
.
: (str "a (1 2) b")
-> (a (1 2) b)
: (str '(a "Hello" DEF))
-> "a \"Hello\" DEF"
(strip 'any) -> any
quote
symbols from any
.
: (strip 123)
-> 123
: (strip '''(a))
-> (a)
: (strip (quote quote a b c))
-> (a b c)
(str? 'any) -> sym | NIL
any
when it is a transient symbol
(string), otherwise NIL
. See also sym?
, box?
and ext?
.
: (str? 123)
-> NIL
: (str? '{ABC})
-> NIL
: (str? 'abc)
-> NIL
: (str? "abc")
-> "abc"
(sub? 'sym1 'sym2) -> flg
NIL
when the name of the first symbol
sym1
is a substring of the name of the second symbol
sym2
. See also pre?
.
: (sub? "def" "abcdef")
-> T
: (sub? "abb" "abcdef")
-> NIL
: (sub? "" "abcdef")
-> T
(sum 'fun 'lst ..) -> num
fun
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to fun
. Returns the sum of all numeric values returned from
fun
.
: (setq A 1 B 2 C 3)
-> 3
: (sum val '(A B C))
-> 6
: (sum # Total size of symbol list values
'((X)
(and (pair (val X)) (size @)) )
(what) )
-> 32021
(super ['any ..]) -> any
This
, this time starting the search for a method at the
superclass(es) of the class where the current method was found.
(dm stop> () # 'stop>' method of current class
(super) # Call the 'stop>' method of the superclass
... ) # other things
(sym 'any) -> sym
any
into the name of a
new symbol sym
. See also any
,
name
and str
.
: (sym '(abc "Hello" 123))
-> "(abc \"Hello\" 123)"
(sym? 'any) -> flg
T
when the argument any
is a symbol. See
also str?
, box?
and ext?
.
: (sym? 'a)
-> T
: (sym? NIL)
-> T
: (sym? 123)
-> NIL
: (sym? '(a b))
-> NIL
(sync) -> flg
tell
mechanism), a
select
system call is executed for all file descriptors and timers
in the VAL
of the global variable *Run
. See also key
and
wait
.
: (or (lock) (sync)) # Ensure database consistency
-> T # (numeric process-id if lock failed)
(sys 'any ['any]) -> sym
: (sys "TERM") # Get current value
-> "xterm"
: (sys "TERM" "vt100") # Set new value
-> "vt100"
: (sys "TERM")
-> "vt100"
T
T
is commonly returned
as the boolean value "true" (though any non-NIL
values could be
used). As a property key, it is used to store Pilog
clauses, and inside Pilog clauses it is the cut operator. See also
NIL
.
: T
-> T
: (= 123 123)
-> T
: (get 'not T)
-> ((@P (1 -> @P) T (fail)) (@P))
This
with
statement. As it is a normal symbol, however, it can be used in normal bindings
anywhere.
: (with 'X (println 'This 'is This))
This is X
-> X
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (put 'Y 'a 111)
-> 111
: (put 'Y 'b 222)
-> 222
: (mapcar '((This) (cons (: a) (: b))) '(X Y))
-> ((1 . 2) (111 . 222))
(t . prg) -> T
prg
, and returns T
. See also nil
, prog
, prog1
and prog2
.
: (t (println 'Ok))
Ok
-> T
(tail 'cnt|lst 'lst) -> lst
cnt
elements of lst
. If
cnt
is negative, it is added to the length of lst
. If
the first argument is a lst
, tail
is a predicate
function returning that argument list if it is equal
to the tail of
the second argument, and NIL
otherwise. See also head
. (tail -2 Lst)
is equivalent to
(nth Lst 3)
.
: (tail 3 '(a b c d e f))
-> (d e f)
: (tail -2 '(a b c d e f))
-> (c d e f)
: (tail 0 '(a b c d e f))
-> NIL
: (tail 10 '(a b c d e f))
-> (a b c d e f)
: (tail '(d e f) '(a b c d e f))
-> (d e f)
(tell 'sym ['any ..]) -> any
(sym any ..)
to all family
members (i.e. all children of the current process, and all other children of the
parent process, see fork
) for automatic
execution. tell
can also be used by commit
to notify about database changes. See also
rpc
and hear
.
: (call 'ps "x") # Show processes
PID TTY STAT TIME COMMAND
..
1321 pts/0 S 0:00 bin/picolisp .. # Parent process
1324 pts/0 S 0:01 bin/picolisp .. # First child
1325 pts/0 S 0:01 bin/picolisp .. # Second child
1326 pts/0 R 0:00 ps x
-> T
: *Pid # We are the second child
-> 1325
: (tell 'println '*Pid) # Ask all others to print their Pid's
1324
-> *Pid
(text 'sym 'any ..) -> sym
sym
, by replacing
all occurrences of an at-mark "@
", followed by one of the letters
"1
" through "9
", and "A
" through
"Z
", with the corresponding any
argument. In this
context "@A
" refers to the 10th argument. A literal at-mark in the
text can be represented by two successive at-marks. See also pack
and glue
.
: (text "abc @1 def @2" 'XYZ 123)
-> "abc XYZ def 123"
: (text "a@@bc.@1" "de")
-> "a@bc.de"
(throw 'sym 'any)
catch
environment with the jump label sym
(or T
as a
catch-all). Any pending finally
expressions
are executed, local symbol bindings are restored, open files are closed and
internal data structures are reset appropriately, as the environment was at the
time when the corresponding catch
was called. Then any
is returned from that catch
.
: (de foo (N)
(println N)
(throw 'Ok) )
-> foo
: (let N 1 (catch 'Ok (foo 7)) (println N))
7
1
-> 1
(tick (cnt1 . cnt2) . prg) -> any
prg
, then (destructively) adds the number of elapsed
user ticks to the cnt1
parameter, and the number of elapsed system
ticks to the cnt2
parameter. Thus, cnt1
and
cnt2
will finally contain the total number of user and system time
ticks spent in prg
and all functions called (this works also for
recursive functions). For execution profiling, tick
is usually
inserted into words with prof
, and removed with
unprof
. See also usec
.
: (de foo () # Define function with empty loop
(tick (0 . 0) (do 100000000)) )
-> foo
: (foo) # Execute it
-> NIL
: (pp 'foo)
(de foo NIL
(tick (97 . 0) (do 100000000)) ) # 'tick' incremented 'cnt1' by 97
-> foo
(till 'any ['flg]) -> lst|sym
any
is found. If flg
is NIL
, a list of
single-character transient symbols is returned. Otherwise, a single string is
returned. See also from
and line
.
: (till ":")
abc:def
-> ("a" "b" "c")
: (till ":" T)
abc:def
-> "abc"
(time ['T]) -> tim
(time 'tim) -> (h m s)
(time 'h 'm ['s]) -> tim | NIL
(time '(h m [s])) -> tim | NIL
T
argument, the current Coordinated Universal
Time (UTC) is returned. When called with a single number tim
, it is
taken as a time value and a list with the corresponding hour, minute and second
is returned. When called with two or three numbers (or a list of two or three
numbers) for the hour, minute (and optionally the second), the corresponding
time value is returned (or NIL
if they do not represent a legal
time). See also date
and usec
.
: (time) # Now
-> 32334
: (time 32334) # Now
-> (8 58 54)
: (time 25 30) # Illegal time
-> NIL
(touch 'sym) -> sym
sym
is an external symbol, it is marked as "modified" so
that upon a later commit
it will be written
to the database file. An explicit call of touch
is only necessary
when the value or properties of sym
are indirectly modified.
: (get '{2} 'lst)
-> (1 2 3 4 5)
: (set (cdr (get (touch '{2}) 'lst)) 999) # Only read-access, need 'touch'
-> 999
: (get '{2} 'lst) # Modified second list element
-> (1 999 3 4 5)
(trace 'sym) -> sym
(trace 'sym 'cls) -> sym
(trace '(sym . cls)) -> sym
$
trace function call at the beginning
of the function or method body of sym
, so that trace information
will be printed before and after execution. Built-in functions
(C
-function pointer) are automatically converted to Lisp
expressions.
: (trace '+)
-> +
: (+ 3 4)
+ : 3 4
+ = 7
-> 7
(trim 'lst) -> lst
lst
with all trailing white space characters
or NIL
elements removed. See also clip
.
: (trim (1 NIL 2 NIL NIL))
-> (1 NIL 2)
: (trim '(a b " " " "))
-> (a b)
(try 'msg 'any ['any ..]) -> any
msg
to the object obj
,
optionally with arguments any
. If any
is not an
object, or if the message cannot be located in obj
, its classes and
superclasses, NIL
is returned. See also send
and method
.
: (try 'msg> 123)
-> NIL
: (try 'html> 'a)
-> NIL
(type 'any) -> lst
sym
. See also
isa
.
: (type '{1A;3})
(+Address)
(udp 'any1 'cnt 'any2) -> any
(udp 'cnt) -> any
any2
is sent to a UDP server listening at host any1
,
port cnt
. In the second form, one item is received from a UDP
socket cnt
, established with port
.
See also connect
.
# First session
: (port T 6666)
-> 3
: (udp 3) # Receive a datagram
# Second session (on the same machine)
: (udp "localhost" 6666 '(a b c))
-> (a b c)
# First session
-> (a b c)
(unify 'any) -> lst
any
with the current Pilog
environment at the current level and with a value of NIL
, and
returns the new environment or NIL
if not successful. See also
prove
and ->
.
: (? (@A unify '(@B @C)))
@A=(((NIL . @C) 0 . @C) ((NIL . @B) 0 . @B) T)
(unless 'any . prg) -> any
any
evaluates to
non-NIL
, NIL
is returned. Otherwise prg
is executed and the result returned. See also when
.
: (unless (= 3 3) (println 'Strange 'result))
-> NIL
: (unless (= 3 4) (println 'Strange 'result))
Strange result
-> result
(until 'any . prg) -> any
any
evaluates to
NIL
, prg
is repeatedly executed. If prg
is never executed, NIL
is returned. Otherwise the result of
prg
is returned. See also while
.
: (until (=T (setq N (read)))
(println 'square (* N N)) )
4
square 16
9
square 81
T
-> 81
(up sym ['val]) -> any
sym
in the
enclosing environment. See also eval
, run
and env
.
: (let N 1 ((quote (N) (println N (up N))) 2))
2 1
-> 1
: (let N 1 ((quote (N) (println N (up N) (up N 7))) 2) N)
2 1 7
-> 7
(upp? 'any) -> sym | NIL
any
when the argument is a string (symbol) that starts
with an uppercase character. See also uppc
.
: (upp? "A")
-> T
: (upp? "a")
-> NIL
: (upp? 123)
-> NIL
: (upp? ".")
-> NIL
(uppc 'any) -> any
any
is not a symbol, it is returned
as it is. Otherwise, a new transient symbol with all characters of
any
, converted to upper case, is returned. See also lowc
, fold
and upp?
.
: (uppc 123)
-> 123
: (uppc "abc")
-> "ABC"
: (uppc 'car)
-> "CAR"
(use sym . prg) -> any
(use (sym ..) . prg) -> any
sym
- or the
values of the symbols sym
in the list of the second form - are
saved, prg
is executed, then the symbols are restored to their
original values. During execution of prg
, the values of the symbols
can be temporarily modified. The return value is the result of prg
.
See also bind
, job
and let
.
: (setq X 123 Y 456)
-> 456
: (use (X Y) (setq X 3 Y 4) (* X Y))
-> 12
: X
-> 123
: Y
-> 456
(usec) -> num
time
and tick
.
: (usec)
-> 1154702479219050
(val 'var) -> any
var
.
: (setq L '(a b c))
-> (a b c)
: (val 'L)
-> (a b c)
: (val (cdr L))
-> b
(wait ['cnt] . prg) -> any
prg
returns non-NIL
, a select
system call is executed for
all file descriptors and timers in the VAL
of the global variable
*Run
. When cnt
is
non-NIL
, the waiting time is limited to cnt
milliseconds. See also key
and sync
.
: (wait 2000) # Wait 2 seconds
-> NIL
: (prog
(zero *Cnt)
(setq *Run # Install background loop
'((-2000 0 (println (inc '*Cnt)))) ) # Increment '*Cnt' every 2 sec
(wait NIL (> *Cnt 6)) # Wait until > 6
(off *Run) )
1 # Waiting ..
2
3
4
5
6
7
-> NIL
(when 'any . prg) -> any
any
evaluates to
non-NIL
, prg
is executed and the result is returned.
Otherwise NIL
is returned. See also unless
.
: (when (> 4 3) (println 'Ok) (println 'Good))
Ok
Good
-> Good
(while 'any . prg) -> any
any
evaluates to
non-NIL
, prg
is repeatedly executed. If
prg
is never executed, NIL
is returned. Otherwise the
result of prg
is returned. See also until
.
: (while (read)
(println 'got: @) )
abc
got: abc
1234
got: 1234
NIL
-> 1234
(wipe 'sym|lst) -> sym|lst
VAL
and the property list of sym
, or of
all symbols in the list lst
. When a symbol is an external symbol,
its state is also set to "not loaded". Does nothing when sym
is an
external symbol that has been modified or deleted ("dirty").
: (setq A (1 2 3 4))
-> (1 2 3 4)
: (put 'A 'a 1)
-> 1
: (put 'A 'b 2)
-> 2
: (show 'A)
A (1 2 3 4)
b 2
a 1
-> A
: (wipe 'A)
-> A
: (show 'A)
A NIL
-> A
(with 'sym . prg) -> any
This
and sets it to the new value
sym
. Then prg
is executed, and This
is
restored to its previous value. The return value is the result of
prg
. Used typically to access the local data of sym
in
the same manner as inside a method body. prg
is not executed (and
NIL
is returned) when sym
is NIL
.
(with 'X . prg)
is equivalent to (let? This 'X . prg)
.
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (with 'X (list (: a) (: b)))
-> (1 2)
(wr 'num ..) -> num
num
arguments as raw bytes to the current output
channel. See also rd
and pr
.
: (out "x" (wr 1 255 257)) # Write to "x"
-> 257
: (hd "x")
00000000 01 FF 01 ...
-> NIL
(xchg 'var 'var ..) -> any
var
argument pairs.
: (setq A 1 B 2 C '(a b c))
-> (a b c)
: (xchg 'A C 'B (cdr C))
-> 2
: A
-> a
: B
-> b
: C
-> (1 2 c)
(xor 'any 'any) -> flg
NIL
.
: (xor T NIL)
-> T
: (xor T T)
-> NIL
(x| 'num ..) -> num
XOR
of all num
arguments. See
also &
, |
and
bit?
.
: (x| 2 7)
-> 5
: (x| 2 7 1)
-> 4
(zap 'sym) -> sym
sym
. For internal symbols, that means to
remove it from the internal hash table, effectively transforming it to a
transient symbol. For external symbols, it means to mark it as "deleted", so
that upon a later commit
it will be removed
from the database file. See also intern
.
: (de foo (Lst) (car Lst)) # 'foo' calls 'car'
-> foo
: (zap 'car) # Delete the symbol 'car'
-> "car"
: (pp 'foo)
(de foo (Lst)
("car" Lst) ) # 'car' is now a transient symbol
-> foo
: (foo (1 2 3)) # 'foo' still works
-> 1
: (car (1 2 3)) # Reader returns a new 'car' symbol
!? (car (1 2 3))
car -- Undefined
?
(zero sym ..) -> 0
0
in the VAL
's of all argument symbols
sym
. See also one
, on
, off
and onOff
.
: (zero A B)
-> 0
: A
-> 0
: B
-> 0
(! . prg) -> any
prg
is
displayed, and a read-eval-print-loop is entered (with !
as its
prompt character), to evaluate expressions and examine the current program
environment. An empty input line terminates the read-eval-print-loop, the
environment and I/O channels are restored, and the result of prg
is
returned. !
is normally inserted into existing programs with the
debug
function. See also e
, ^
and *Dbg
.
: (de foo (N) (and (println 1) (! println N) (println 2)))
-> foo
: (foo 7)
1 # Executed '(println 1)'
(println N) # Entered breakpoint
! N # Examine the value of 'N'
-> 7
! (e) # Evaluate '^', i.e. (println N)
7
-> 7
! (e @) # Evaluate '@' -> the result of '(println 1)'
-> 1
! # Empty line: continue
7 # Executed '(println N)'
2 # Executed '(println 2)'
-> 2
($ sym|lst lst . prg) -> any
sym|lst
is printed
to the console with a proper indentation, followed by a colon :
. If
a function is traced, the first argument is the function symbol, else if a
method is traced, it is a cons pair of message and class. The second argument
lst
should be a list of symbols, identical to the function's
argument list. The current values of these symbols are printed, followed by a
newline. Then prg
is executed, and its return value printed in a
similar way (this time with an equals sign =
instead of a colon)
and returned. $
is normally inserted into existing programs with
the trace
function.
: (de foo (A B) ($ foo (A B) (* A B)))
-> foo
: (foo 3 4)
foo : 3 4 # Function entry, arguments 3 and 4
foo = 12 # Function exit, return value 12
-> 12
(% 'num ..) -> num
num
arguments. The sign of the result is that of the first argument.
: (% 17 5)
-> 2
: (% -17 5) # Sign is that of the first argument
-> -2
: (% 5 2)
-> 1
: (% 15 10)
-> 5
: (% 15 10 2) # (% 15 10) -> 5, then (% 5 2) -> 1
-> 1
(& 'num ..) -> num
AND
of all num
arguments. See
also |
, x|
and
bit?
.
: (& 6 3)
-> 2
: (& 7 3 1)
-> 1
(* 'num ..) -> num
num
arguments.
: (* 1 2 3)
-> 6
: (* 5 3 2 2)
-> 60
(*/ 'num1 ['num2 ..] 'num3) -> num
num1
and all following num2
arguments, divided by the num3
argument. The result is rounded to
the nearest integer value.
: (*/ 3 4 2)
-> 6
: (*/ 1234 2 10)
-> 247
: (*/ 100 6)
-> 17
*Adr
listen
and accept
.
: *Adr
-> "127.0.0.1"
*Bye
prg
body, to be
executed just before the termination of the Pico Lisp interpreter.
: (push '*Bye '(call 'rm "-r" *Tmp)) # Remove all temporary files
-> (call 'rm "-r" *Tmp)
*Class
: (class +Test)
-> +Test
: *Class
-> +Test
*DB
{1}
, the database
root. All transient symbols in a database can be reached from that root. Except
during debugging, any explicit literal access to symbols in the database should
be avoided, because otherwise a memory leak might occur (The garbage collector
temporarily sets *DB
to NIL
and restores its value
after collection, thus disposing of all external symbols not currently used in
the program).
: (show *DB)
{1} NIL
+City {P}
+Person {3}
-> {1}
: (show '{P})
{P} NIL
nm (566 . {AhDx})
-> {P}
: (show '{3})
{3} NIL
tel (681376 . {Agyl})
nm (1461322 . {2gu7})
-> {3}
*Dbg
$
(tracing)
and !
(breakpoint) functions. They are enabled
when *Dbg
is non-NIL
.
: (de foo (A B) (* A B))
-> foo
: (trace 'foo)
-> foo
: (foo 3 4)
foo : 3 4
foo = 12
-> 12
: (let *Dbg NIL (foo 3 4))
-> 12
*Err
prg
body, which
will be executed during error processing. See also Error
Handling
, *Rst
and *Msg
.
: (de *Err (prinl "Fatal error!"))
-> ((prinl "Fatal error!"))
: (/ 3 0)
!? (/ 3 0)
Div/0
Fatal error!
$
*Fork
prg
body, to be
executed after a call to fork
in the child
process.
: (push '*Fork '(off *Tmp)) # Clear '*Tmp' in child process
-> (off *Tmp)
*Led
prg
body that
implements a "Line editor". When non-NIL
, it should return a single
symbol (string) upon execution.
: (de *Led "(bye)")
# *Led redefined
-> *Led
: $ # Exit
*Msg
Error Handling
, *Err
and *Rst
.
: (+ 'A 2)
!? (+ 'A 2)
A -- Number expected
?
:
: *Msg
-> "Number expected"
*PPid
NIL
if the current process is a top level process.
: (println *PPid *Pid)
NIL 5286
: (unless (fork) (println *PPid *Pid) (bye))
5286 5522
*Pid
: *Pid
-> 6386
: (call "ps") # Show processes
PID TTY TIME CMD
.... ... ........ .....
6386 pts/1 00:00:00 bin/picolisp # <- current process
6388 pts/1 00:00:00 ps
-> T
*Rst
prg
body, which
will be executed after error processing. This makes it possible to restart an
application despite of a failure. See also Error
Handling
, *Err
and *Msg
.
: (de loopTest ()
(let N 4
(loop
(println (/ 100 (dec 'N))) ) ) )
-> loopTest
: (de *Rst
(prinl "Loop Failed!")
(wait 4000)
(loopTest) ) # restart
-> *Rst
: (loopTest)
33
50
100
!? (/ 100 (dec 'N))
Div/0
Loop Failed!
33
50
100
!? (/ 100 (dec 'N))
Div/0
Loop Failed!
...
*Run
prg
expressions which
are used during key
, sync
and wait
. The
first element of each expression must either be a positive number (thus denoting
a file descriptor to wait for) or a negative number (denoting a timeout value in
milliseconds (in that case another number must follow to hold the remaining
time)). A select
system call is performed with these values, and
the corresponding prg
body is executed when input data are
available or when a timeout occurred.
: (de *Run (-2000 0 (println '2sec))) # Install 2-sec-timer
-> *Run
: 2sec # Prints "2sec" every 2 seconds
2sec
2sec
# (Enter) Exit
$
*Scl
Numbers
. The value can be locally overridden
with the scl
function:
: (pp 'scl)
(de scl (*Scl . "Prg")
(run "Prg") )
-> scl
: (str "123.45") # Default value of '*Scl' is 0
-> (123)
: (scl 0 (str "123.45"))
-> (123)
: (scl 3 (str "123.45"))
-> (123450)
*Solo
0
initially, set to T
(or NIL
) during
cooperative database locks when lock
is
successfully called with a NIL
(or non-NIL
) argument.
: *Solo
-> 0
: (lock *DB)
-> NIL
: *Solo
-> NIL
: (rollback)
-> T
: *Solo
-> 0
: (lock)
-> NIL
: *Solo
-> T
: (rollback)
-> T
: *Solo
-> T
*Uni
,
) read-macro. See also Read-Macros
.
: (off *Uni) # Clear
-> NIL
: ,"abc" # Collect a transient symbol
-> "abc"
: ,(1 2 3) # Collect a list
-> (1 2 3)
: *Uni
-> ((1 2 3) "abc")
(+ 'num ..) -> num
num
arguments.
: (+ 1 2 3)
-> 6
(- 'num ..) -> num
num
argument and all
following arguments. If only a single argument is given, it is negated.
: (- 7)
-> -7
: (- 7 2 1)
-> 4
(/ 'num ..) -> num
num
argument successively divided by all
following arguments.
: (/ 12 3)
-> 4
: (/ 60 3 2 2)
(: sym|0 [sym1|cnt ..]) -> any
any
from the properties of a symbol, or from a
list, by applying the get
algorithm to
This
and the following arguments. Used typically in methods or
with
bodies. See also get
, =:
and ::
.
: (put 'X 'a 1)
-> 1
: (with 'X (: a))
-> 1
(:: sym [sym1|cnt .. sym2]) -> lst|sym
sym
or sym2
from a symbol. That symbol is This
(if no other arguments are
given), or a symbol found by applying the get
algorithm to This
and the following arguments. The property (the
cell, not just its value) is returned, suitable for direct (destructive)
manipulations. Used typically in methods or with
bodies. See also =:
and :
.
: (with 'X (=: cnt 0) (inc (:: cnt)) (: cnt))
-> 1
(< 'any ..) -> flg
T
when all arguments any
are in strictly
increasing order. See also Comparing.
: (< 3 4)
-> T
: (< 'a 'b 'c)
-> T
: (< 999 'a)
-> T
(<= 'any ..) -> flg
T
when all arguments any
are in strictly
non-decreasing order. See also Comparing.
: (<= 3 3)
-> T
: (<= 1 2 3)
-> T
: (<= "abc" "abc" "def")
-> T
(<> 'any ..) -> flg
T
when not all any
arguments are equal
(structure equality). (<> 'any ..)
is equivalent to (not (=
'any ..))
. See also Comparing.
: (<> 'a 'b)
-> T
: (<> 'a 'b 'b)
-> T
: (<> 'a 'a 'a)
-> NIL
(= 'any ..) -> flg
T
when all any
arguments are equal
(structure equality). See also Comparing.
: (= 6 (* 1 2 3))
-> T
: (= "a" "a")
-> T
: (== "a" "a")
-> T
: (= (1 (2) 3) (1 (2) 3))
-> T
(=0 'any) -> num | NIL
0
when any
is a number with value zero.
See also n0
, lt0
,
ge0
and gt0
.
: (=0 (- 6 3 2 1))
-> 0
: (=0 'a)
-> NIL
(=: sym [sym1|cnt .. sym2] 'any)
any
for a property key sym
or
sym2
in a symbol. That symbol is This
(if no other
arguments are given), or a symbol found by applying the get
algorithm to This
and the following
arguments. Used typically in methods or with
bodies. See also put
, :
and ::
.
: (with 'X (=: a 1) (=: b 2))
-> 2
: (get 'X 'a)
-> 1
: (get 'X 'b)
-> 2
(== 'any ..) -> flg
T
when all any
arguments are the same
(pointer equality). See also n==
.
: (== 'a 'a)
-> T
: (== 'NIL NIL (val NIL) (car NIL) (cdr NIL))
-> T
: (== 6 (* 1 2 3))
-> NIL
(==== ['sym ..]) -> NIL
sym
arguments are inserted into the transient hash table.
See also extern
and intern
.
: (setq S "abc") # Read "abc"
-> "abc"
: (== S "abc") # Read again, get the same symbol
-> T
: (====) # Close scope
-> NIL
: (== S "abc") # Read again, get another symbol
-> NIL
(=T 'any) -> flg
T
when any
is the symbol T
.
(=T X)
is equivalent to (== T X)
. See also nT.
: (=T 0)
-> NIL
: (=T "T")
-> NIL
: (=T T)
-> T
(> 'any ..) -> flg
T
when all arguments any
are in strictly
decreasing order. See also Comparing.
: (> 4 3)
-> T
: (> 'A 999)
-> T
(>= 'any ..) -> flg
T
when all arguments any
are in strictly
non-increasing order. See also Comparing.
: (>= 'A 999)
-> T
: (>= 3 2 2 1)
-> T
(>> 'cnt 'num) -> num
num
argument by cnt
bit-positions. If cnt
is negative, a corresponding left shift is
performed.
: (>> 1 8)
-> 4
: (>> 3 16)
-> 2
: (>> -3 16)
-> 128
: (>> -1 -16)
-> -32
(? [sym 'any ..] . lst) -> flg
: (? (append (a b c) (d e f) @X))
@X=(a b c d e f)
-> NIL
: (? (append @X @Y (a b c)))
@X=NIL @Y=(a b c)
@X=(a) @Y=(b c)
@X=(a b) @Y=(c)
@X=(a b c) @Y=NIL
-> NIL
: (? (append @X @Y (a b c)))
@X=NIL @Y=(a b c). # Stopped
-> NIL
@
@ Result
).
When @
is used as a formal parameter in lambda
expressions, it denotes a variable number of evaluated arguments.
@@
@ Result
).
@@@
@ Result
).
^
debug
, !
,
e
and *Dbg
.
: (* (+ 3 4) (/ 7 0))
!? (/ 7 0)
Div/0
? ^
-> (/ 7 0)
(| 'num ..) -> num
OR
of all num
arguments. See
also x|
, &
and
bit?
.
: (| 1 2)
-> 3
: (| 1 2 4 8)
-> 15
The Pico Lisp
system can be downloaded from the Pico Lisp Download page.