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
CARs 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 symol'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 path name to the first command line file argument 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 orignial 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 preceeded 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 be 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.
In an interactive environment (console), transient symbols should appear as
an underlined sequence of characters. Where this is not possible (e.g.
for representation in files), or inconvenient (while editing), double quotes
'"' are used instead of - or in addition to - underlining.
A transient symbol may be used (and, in double quote representation, also look) 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 loading 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 achived 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)
-> '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))))
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 evalutes 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 symols 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 argumens 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 *Key tasks.
@ is generally local to functions and methods, its vaule 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 aggreement 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 symols 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. At a time, only one database file can
be open (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, valuees, 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 compatibile 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
sp?
pat?
fun?
intern
extern
====
box?
str?
ext?
touch
zap
length
size
format
chop
pack
pre?
sub?
low?
upp?
lowc
uppc
fold
val
set
setq
def
de
dm
xchg
on
off
onOff
zero
one
default
let
let?
use
push
pop
cut
del
queue
idx
lup
put
get
prop
=:
:
::
putl
getl
wipe
meta
atom
pair
lst?
num?
sym?
flg?
sp?
pat?
fun?
box?
str?
ext?
==
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
index
offset
assoc
asoq
rank
sort
length
size
val
set
xchg
push
pop
cut
queue
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
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
pool
journal
begin
commit
rollback
lieu
lock
id
seq
mark
dbck
rel
be
goal
prove
->
unify
?
stat
debug
trace
argv
opt
gc
raw
protect
heap
env
up
stk
stat
date
time
stamp
cd
ctty
info
dir
call
tick
kill
quit
fork
bye
NIL
*DB
*Solo
^
@
@@
@@@
This
T
*Dbg
*Pid
*Scl
*Class
*Key
*Led
*Tsm
*Err
*Rst
*Msg
*Uni
*Adr
*Fork
*Bye
(abs 'num) -> num
num argument.
: (abs -7)
-> 7
: (abs 7)
-> 7
(accept 'cnt) -> cnt | NIL
cnt (as recieved 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 charactoer
: (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 loading 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 consing 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]) -> flg
begin are taken into account. A non-NIL
argument forces modifications of the current transaction level to be written
out, even if this is not the top level. When the argument is anything other than
T, it is implicitly sent (with all modified objects) via the
tell mechanism to all family members. 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.
: (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. See also in, pipe and out.
$ echo 9 >count # Write '9' to file "count"
$ ./p dbg.l
: (ctl "count" # Get exclusive control
(in "count"
(let Cnt (read) # Read '9'
(out "count"
(println (- Cnt 1)) ) ) ) ) # 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 numers (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 ['num] 'flg) -> any
num'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 after allocating external symbols
with new) 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)
(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 geting 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 exution 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.
: (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? 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.
: (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
(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. 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.
: (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
(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 uppc and 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
(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, that number of
megabytes of free cells is reserved, increasing the heap size if necessary.
: (gc)
-> NIL
: (stat)
0.6 32%
-> 54827
: (gc 4)
-> 4
: (stat)
4.3 5%
-> 534802
(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 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 '(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))
(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. If it is a positive number,
it is used as the descriptor of an open file. If it is a negative number, the
saved input channel such many levels above the current one is used. 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 *Key task. See also 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 *Key. 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,
subsequenct 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 'sym ..) -> cnt
sym. 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 recieved 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 *Key. 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 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
consing 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 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. 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 'lst 'lst) -> lst
lst argument as a pattern to be matched against
the second lst, 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.
: (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
(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))
(T (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 positve number, it is used
as the descriptor of an open file. If it is a negative number, the saved output
channel such many levels above the current one is used. 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.
: (pack 'car " is " 1 '(" symbol " name))
-> car is 1 symbol name
(pair 'any) -> flg
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 proces)
-> 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 256 byte block size(s)). 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 cut and del.
: (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 'cnt|lst ['var]) -> cnt
cnt, and returns a socket descriptor. If
cnt is zero, some free port number is allocated. If a
lst is given instead, it should be a list 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 4001 4002 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 propery 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.
: (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)
(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.
: (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) -> 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. NIL is returned upon end of file. See also pr, wr and 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
(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.
: (stop> Dlg)
-> NIL
(seq 'sym1 ['sym2 ['num]]) -> sym | num | NIL
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.
: (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)
0.6 32%
-> 264813
(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 *Key. 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 normale 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
(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. See also finally.
: (de foo (N)
(println N)
(throw 'Ok) )
-> foo
: (let N 1 (catch 'Ok (foo 7)) (println N))
7
1
-> 1
(tick cnt . prg) -> any
prg, then (destructively) adds the number of elapsed
ticks locally to the cnt parameter. Thus, cnt will
finally contain the total number of 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.
: (de foo () # Define function with empty loop
(tick 0 (do 100000000)) )
-> foo
: (foo) # Execute it
-> NIL
: (pp 'foo)
(de foo NIL
(tick 97 (do 100000000)) ) # `tick' incremented `cnt' 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 numers (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.
: (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.
: (try 'msg> 123)
-> NIL
: (try 'html> 'a)
-> NIL
(type 'any) -> lst
sym. See also
isa.
: (type '{1A;3})
(+Address)
(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
(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
*Key. When cnt is
non-NIL, the waiting time is limited to cnt
milliseconds. See also key and sync.
: (wait 2000) # Sleep for 2 seconds
-> NIL
: (prog
(zero *Cnt)
(setq *Key # Install background loop
'((-2000 0 (println (inc '*Cnt)))) ) # Increment `*Cnt' every 2 sec
(wait NIL (> *Cnt 6)) # Wait until > 6
(off *Key) )
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)
*Key
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 remaning
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 *Key (-2000 0 (println '2sec))) # Install 2-sec-timer
-> *Key
: 2sec # Prints "2sec" every 2 seconds
2sec
2sec
# (Enter) Exit
$
*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
*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!
...
*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
*Tsm
print will output these sequences to the
console instead of the standard double quote markup characters.
: (de *Tsm "^[[4m" . "^[[24m") # vt100 escape sequences for underline
-> *Tsm
: "Hello world"
-> Hello world
: (off *Tsm)
-> NIL
: "Hello world" # No underlining
-> "Hello world"
*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.