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.
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 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 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 system should be
An important point in the Pico 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 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 supports exactly three base data
types (Numbers, Symbols and Cons Pairs (Lists)), the three variations of
symbol types (Internal, Transient and External), and the special symbol
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 Pair
|
+--------+--------+--------+
| | | |
Internal Transient External NIL
A number can represent a signed integral value of arbitrary size. The
CAR
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, or 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
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 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, this cell is
called a "dotted pair" (because of its I/O syntax with a dot '.' between the two
values).
The Pico 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 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 inherits the major advantages of classical Lisp systems like
In the following, some concepts and peculiarities of the Pico language and environment are described.
When Pico 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 load
ed by the interpreter. If, however, the argument's
first character is a hyphen '-', then 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).
As a convention, Pico source files have the extension ".l
".
The simplest and shortest invocation of Pico does nothing, and exits
immediately by calling bye
:
$ bin/pico -bye
$
In interactive mode, the Pico interpreter (see load
) will also exit when an empty line is entered:
$ bin/pico
:
$
To start up the standard Pico 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/pico 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 Home Directory. This path is later
automatically substituted for any leading "@
" character in file
name arguments to I/O functions.
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 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 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.
A transient symbol is anything surrounded by double quotes '"
'.
With that, it looks - and can be used - like a string constant in other
languages. However, it is a real symbol, and may be assigned a value or a
function definition, and properties.
Initially, a transient symbol's value is that symbol itself, so that it does not need to be quoted for evaluation:
: "This is a string"
-> "This is a string"
However, care must be taken when assigning a value to a transient symbol. This may cause unexpected behavior:
: (setq "This is a string" 12345)
-> 12345
: "This is a string"
-> 12345
The name of a transient symbol can contain any character. A double quote
character can be escaped with a backslash '\
', and a backslash
itself has to be escaped with another backslash. Control characters can be
written with a preceding hat '^
' character.
: "We^Ird\\Str\"ing"
-> "We^Ird\\Str\"ing"
: (chop @)
-> ("W" "e" "^I" "r" "d" "\\" "S" "t" "r" "\"" "i" "n" "g")
The hash table for transient symbols is cleared automatically before and
after load
ing a source file, or it can be reset
explicitly with the ====
function. With that
mechanism, it is possible to create symbols with a local access scope, not
accessible from other parts of the program.
It is possible to create transient symbols without a name (see box
or new
). These
symbols print as a decimal digit string (actually their machine address)
enclosed in double quotes.
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 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 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 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 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 it 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 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 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.
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 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
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, closes all files,
displays the location of the error 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. Then, if the standard input is not from a terminal, the
interpreter terminates. Otherwise a read-eval-print loop (with a question mark
"?
" as prompt) is entered (the loop is exited when an empty line is
input), and finally all variable bindings and the interpreter are reset to their
top-level state.
: (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
These functions include and, case, cond, do, for, if, ifn, nand, nor, or, prog1, prog2, unless, until, when, while and whilst
@
is generally local to functions and methods, its vaule is
automatically saved upon function entry and restored at exit.
In Pico, 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)
Pico comes with built-in object oriented extensions. There seems to be a common aggreement upon three criteria for object orientation:
Pico 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 have names and 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 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 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 a binary search
tree, by holding a key, a value, and links to the left and right subtrees in
their VAL
's. Such a binary 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
+Link
+Hook
+Joint
+List
+Bag
+Ref
+Key
+Idx
+Sn
+Any
It was necessary to introduce - and adhere to - a set of conventions for Pico symbol names. Because all (internal) symbols have a global scope (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 meaning 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 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 the whole unevaluated argument list.
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'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 is a dynamically typed language (resolved at runtime, as opposed to statically (compile-time) typed languages), most 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
tim
- Time: Seconds since midnight
obj
- Object/Class: A symbol with methods and/or classes
var
- Variable: Either a symbol's VAL
or a cell's CAR
exe
- Executable: A list as executable expression (eval
)
prg
- Prog-Body: A list of executable expressions (run
)
foo
- Function: Either a number (code-pointer) 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
str
char
sp?
pat?
fun?
intern
extern
====
str?
ext?
touch
zap
length
size
format
chop
pack
pre?
sub?
upp?
uppc
low?
lowc
val
set
setq
def
de
dm
xchg
on
off
zero
default
let
use
push
pop
cut
queue
put
get
prop
=:
:
::
putl
getl
wipe
meta
atom
pair
lst?
num?
sym?
sp?
pat?
fun?
str?
ext?
==
n==
=
<>
=0
=T
n0
nT
<
<=
>
>=
match
prove
->
unify
+
-
*
/
%
*/
inc
dec
>>
lt0
gt0
abs
bit?
&
|
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
trim
clip
head
tail
last
member
memq
mmeq
index
offset
assoc
asoq
rank
sort
length
size
val
set
xchg
push
pop
cut
queue
get
fill
apply
load
args
next
arg
rest
pass
quote
eval
run
def
de
dm
box
new
type
isa
method
meth
send
super
extra
with
bind
job
let
use
and
or
nand
nor
xor
bool
not
nil
t
prog
prog1
prog2
if
ifn
when
unless
cond
case
while
whilst
until
do
at
for
catch
throw
!
e
$
call
tick
kill
quit
fork
bye
apply
pass
all
maps
map
mapc
maplist
mapcar
mapcon
mapcan
filter
seek
find
pick
cnt
sum
maxi
mini
in
out
load
str
hear
tell
key
peek
char
skip
from
till
line
format
read
print
println
printsp
prin
prinl
space
flush
rewind
rd
pr
wait
sync
echo
info
lines
open
close
port
listen
peer
connect
pool
begin
commit
rollback
lock
seq
mark
dbck
rel
stat
debug
trace
argv
gc
heap
env
stk
stat
date
time
stamp
cd
ctty
info
call
tick
kill
quit
fork
bye
NIL
*DB
^
@
@@
@@@
This
T
*Pid
*Scl
*Class
*Key
*Dbg
*Led
*Err
*Msg
*Bye
(abs 'num) -> num
num
argument.
: (abs -7)
-> 7
: (abs 7)
-> 7
(all 'foo) -> any
foo
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
: (make (all '((X) (and (= "_" (car (chop X))) (link X))))) # Find all symbols
starting with an underscore charactoer
-> (_ed _isa _delL _delR _dbg _del _clone _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
(append 'lst ..) -> lst
: (append '(a b c) (1 2 3))
-> (a b c 1 2 3)
: (append (1) (2) (3) 4)
-> (1 2 3 . 4)
(apply 'foo 'lst ['any ..]) -> any
foo
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) -> any
@
). Returns the current argument from the internal list (the same
that was returned with the last call to next
). See also args
, next
, rest
and pass
.
: (de foo @ (println (next) (arg))) # Print argument twice
-> foo
: (foo 123)
123 123
-> 123
(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) -> lst
-
" can be used to stop load
ing further
arguments.
$ ./p -"println 'Ok" - abc 123
Ok
: (argv)
-> ("abc" "123")
(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 '(num1 . num2) . prg) -> any
num1
(destructively), and returns NIL
when it is less than num2
. Otherwise, prg
is executed
and num1
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).
: (atom 123)
-> T
: (atom 'a)
-> T
: (atom NIL)
-> T
: (atom (123))
-> 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 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 ..) -> flg
T
when all bits which are 1 in the first
num
argument are also 1 in all following num
arguments.
: (bit? 1 2)
-> NIL
: (bit? 1 3)
-> T
: (bit? 7 15 255)
-> T
(bool 'any) -> flg
T
when the evaluation of the any
argument
yields 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").
: (and 3 4)
-> 4
: (bool (and 3 4))
-> T
(box 'any) -> sym
any
argument.
: (show (box '(A B C)))
$134425627 (A B C)
-> $134425627
(bye 'cnt|NIL)
VAL
of the global variable *Bye
(should be a prg
), closes all open
files, and exits Pico. 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,
exeN
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.
: (catch 'Ok (println 1) (throw 'Ok 999) (println 2))
1
-> 999
(cd 'sym) -> flg
sym
.
: (dir "src/*.c")
-> ("src/apply.c" "src/big.c" "src/flow.c" "src/gc.c" "src/io.c" "src/main.c" "src/net.c" "src/subr.c" "src/sym.c" "src/tab.c" "src/z3d.c" "src/z3dClient.c")
: (cd "src")
-> T
: (dir "*.c")
-> ("apply.c" "big.c" "flow.c" "gc.c" "io.c" "main.c" "net.c" "subr.c" "sym.c" "tab.c" "z3d.c" "z3dClient.c")
(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 (usable as a top value for 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
and till
.
: (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
-> "˙"
: (char "d") # Convert symbol to unicode
-> 100
(chop 'sym) -> lst
sym
as a list of single-character strings.
If sym
is NIL
or has no name, NIL
is
returned.
: (chop 'car)
-> ("c" "a" "r")
: (chop "Hello")
-> ("H" "e" "l" "l" "o")
(circ 'lst) -> lst
lst
to
the CDR
of its own last cell.
: (circ '(a b c))
-> (a b c .)
: (setq L1 '(a b c d e f) L2 (1 2 3))
-> (1 2 3)
: (mapc println L1 (circ L2)) # Produce an unlimited supply of L2
a 1
b 2
c 3
d 1
e 2
f 3
-> 3
(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) -> T
cnt
. See also open
, listen
,
connect
.
: (close 2) # Close standard error
-> T
(cnt 'foo 'lst ..) -> cnt
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns the count of non-NIL
values returned
from foo
.
: (cnt cdr '((1 . T) (2) (3 4) (5)))
-> 2
(commit ['flg]) -> flg
begin
are taken into account. A non-NIL
flg
argument forces modifications of the current transaction level
to be written out, even if this is not the top level. When flg
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
: (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
, exeN
is executed and the result returned.
Otherwise (all conditions evaluate to NIL
), NIL
is
returned.
: (cond
((= 3 4) (println 1))
((= 3 3) (println 2))
(T (println 3)) )
2
-> 2
(connect 'sym 'cnt) -> cnt
sym
, port cnt
. sym
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
(ctty 'sym) -> flg
sym
.
: (ctty "/dev/tty")
-> T
(cut 'cnt 'var) -> lst
cnt
elements (CAR
) from the stack
in var
. See also pop
.
: (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) -> dat
(date 'dat) -> (y m d)
(date 'y 'm 'd) -> dat | NIL
(date '(y m d)) -> dat | NIL
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) -> sym | NIL
NIL
if everything seems correct. Otherwise, a string
indicating an error is returned. As a side effect, possible 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
!
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 ^
.
: (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 'var ['num]) -> num
VAL
of var
by 1, or by
num
.
: (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)
(delete 'any 'lst) -> lst
any
from lst
. If any
is
contained more than once in lst
, only the first occurrence is
deleted.
: (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)
(dm sym . foo) -> sym
(dm (sym . cls) . foo) -> 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
. This is
analog to a function definition.
: (dm start> ()
(super)
(mapc '((F) (start> F)) (: fields))
(mapc '((B) (start> B)) (: arrays)) )
(do 'NIL|num .. [(NIL 'any . prg)] .. [(T 'any . prg)] ..) -> any
num
(or infinite, if the first argument is NIL
) times.
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.
: (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
!
and ^
.
: (! + 3 4)
(+ 3 4)
! (e)
-> 7
(echo ['cnt|sym ..]) -> sym
cnt
is given, only that many bytes are actually echoed.
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
stk
.
: (env)
-> NIL
: (de foo (A B C) (! println A B C))
-> foo
: (foo 1 2 3)
(println A B C)
! (env)
-> (A B C)
!
1 2 3
-> 3
(eval 'any) -> any
any
. Note that because of the standard argument
evaluation, any
is actually evaluated twice.
: (eval (list '+ 1 2 3))
-> 6
: (setq X 'Y Y 7)
-> 7
: X
-> Y
: Y
-> 7
: (eval X)
-> 7
(ext? 'any) -> flg
T
when the argument any
is an external
symbol.
: (ext? 123)
-> NIL
: (ext? 'abc)
-> NIL
: (ext? "abc")
-> NIL
: (ext? '{ABC})
-> T
(extern 'sym) -> sym
intern
and ====
.
: (extern "A1b3")
-> {A1b3}
(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) -> any
any
, by substituting each pattern symbol (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))
(filter 'foo 'lst ..) -> lst
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns a list of all elements of lst
where
foo
returned non-NIL
.
: (filter num? (1 A 2 (B) 3 CDE))
-> (1 2 3)
(find 'foo 'lst ..) -> any
foo
to successive elements of lst
until
non-NIL
is returned. Returns that element, or
NIL
if foo
did not return non-NIL
for any
element of lst
. When additional lst
arguments are
given, their elements are also passed to foo
. 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
(flush) -> flg
flush
for standard output is done automatically before a call to
key
. Returns T
when successful. See
also rewind
.
: (flush)
-> T
(for (sym 'any1 'any2 [. prg1]) . prg2) -> any
sym
is
saved, and sym
is bound to any1
. While the condition
any2
evaluates to non-NIL
, prg2
is
repeatedly executed and, if prg1
is given, the sym
is
re-bound to the result of its evaluation. If prg2
is never
executed, NIL
is returned. Otherwise the result of
prg2
is returned.
: (for (N 1 (< N 9) (+ 1 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
(fork) -> pid | NIL
NIL
in the child, and the
child's process ID pid
in the parent. See also 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. If none of
any
is found, NIL
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.
Otherwise 0
is returned for a code-pointer, T
for a
procedure, or the list of formal parameters for other functions.
: (fun? 1000000000) # Might be a code pointer
-> 0
: (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? '(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
(get 'sym1|lst ['sym2|cnt ..] 'sym|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 a property value from a symbol (the next
argument is a symbol, hence the current value must be a symbol) or by extracting
an element from a list (the next argument is a number, hence the current value
must be a list).
: (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.
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (put 'X 'flg T)
-> T
: (getl 'X)
-> (flg (2 . b) (1 . a))
(gt0 'num) -> flg
T
when the num
argument is greater than
zero.
: (gt0 -2)
-> NIL
: (gt0 3)
-> T
(head 'cnt 'lst) -> lst
cnt
elements of
lst
. See also tail
. If
cnt
is negative, it is added to the length of lst
.
: (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)
(heap 'flg) -> cnt
flg
is NIL
), or the total number of cells in
the system (if flg
is non-NIL
).
: (heap)
-> 65948
: (heap T)
-> 131072
(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. As this mechanism is also used for
inter-family communication (see tell
),
hear
should only be called by a top level parent process.
: (hear "fifo/cmd")
-> "fifo/cmd"
(if 'any1 'any2 . prg) -> any
any1
evaluates to
non-NIL
, any2
is evaluated and returned. Otherwise,
prg
is executed and the result returned.
: (if (> 4 3) (println 'Ok) (println 'Bad))
Ok
-> Ok
: (if (> 3 4) (println 'Ok) (println 'Bad))
Bad
-> Bad
(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 number, it is
used as the descriptor of an open file. Otherwise (if it is a list), it is taken
as a command with arguments, and a pipe is opened for input. See also call
, load
and out
.
: (in "a" (list (read) (read) (read))) # Read three items from file "a"
-> (123 (a b c) def)
(inc 'var ['num]) -> num
VAL
of var
by 1, or by
num
.
: (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 'sym) -> (cnt dat . tim)
sym
: The current
size cnt
in bytes, and the modification date and time. See also
date
, time
and
lines
.
$ ls -l x.l
-rw-r--r-- 1 abu users 208 Jun 17 08:58 x.l
$ p
: (info "x.l")
-> (208 730594 . 32315)
: (stamp 730594 32315)
-> "2000-06-17 08:58:35"
(intern 'sym) -> sym
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
. See also bind
, let
and use
.
: (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
(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 wait
.
: (key) # Wait for a key
-> "a" # `a' pressed
(kill 'pid 'cnt) -> flg
cnt
to the process with
the ID pid
. Returns T
if successful.
: (kill *Pid 20) # Stop current process
[2]+ Stopped /usr/abu/pico/p # Unix shell
abu@bse:/usr/abu/pico fg # Job control: Foreground
/usr/abu/pico/p
-> T # `kill' was successful
(last 'lst) -> any
lst
.
: (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 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 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
(line 'flg ['cnt ..]) -> lst|sym
flg
is NIL
,
it returns a list of single-character transient symbols. 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.
T
is returned upon end of file. See also char
and till
.
: (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
. If cnt1
is
non-NIL
, that amount of milliseconds is waited maximally, and
NIL
is returned upon timeout. See also connect
.
(setq *Socket
(listen (port 6789)) ) # Listen at port 6789 for an indefinite time
(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 NIL
and 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
and out
.
: (load "lib/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. The lock is released at the next top level call to commit
or rollback
.
: (lock '{1}) # Lock single object
-> NIL
: (lock) # Lock whole database
-> NIL
(-> sym [num]) -> any
sym
at
top level (or level num
) in the current Pico Prolog (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
(low? 'any) -> flg
T
when the argument any
is a string
(symbol) that starts with a lowercase character.
: (low? "a")
-> T
: (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.
: (lowc 123)
-> 123
: (lowc "ABC")
-> "abc"
(lt0 'num) -> flg
T
when the num
argument is less than zero.
: (lt0 -2)
-> T
: (lt0 3)
-> NIL
(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 'foo 'lst ..) -> lst
foo
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to foo
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 'foo 'lst ..) -> any
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. 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 'foo 'lst ..) -> lst
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. 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 'foo 'lst ..) -> lst
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. 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 'foo 'lst ..) -> lst
foo
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to foo
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 'foo 'lst ..) -> lst
foo
to lst
and all successive
CDR
's. When additional lst
arguments are given, they
are passed to foo
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 'foo 'sym ['lst ..]) -> any
foo
to all properties of sym
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns the result of the last application.
: (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).
If the first argument is zero, all marks are cleared.
: (pool "db")
-> T
: (mark '{1} T) # Mark
-> T
: (mark '{1}) # Test
-> T # -> marked
: (mark '{1} 0) # Unmark
-> NIL
: (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 then bound to the corresponding data. See also
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 'foo 'lst ..) -> any
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns that element from lst
for that
foo
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 (val X)) ) )
(what) )
-> *History
(member 'any 'lst) -> any
lst
that starts with any
when
any
is a member of lst
, otherwise NIL
.
: (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) -> any
any
, by searching the property lists
of the classes and superclasses of obj
, or the classes in
typ
, for the property key sym
.
: (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) -> foo
msg
to the object obj
. If the message
cannot be located in obj
, its classes and superclasses,
NIL
is returned.
: (method 'stop> '+Dialog)
-> (NIL (super) (close> This))
(min 'any ..) -> any
any
arguments. See also Comparing.
: (min 2 'a 'z 9)
-> 2
: (min (5) (2 3) 'X)
-> X
(mini 'foo 'lst ..) -> any
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns that element from lst
for that
foo
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 ..))
.
: (n== 'a 'a)
-> NIL
: (n== 1 1)
-> T
(n0 'any) -> flg
T
when any
is not a number with value
zero. See also =0.
: (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
(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 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] ['typ ['any ..]]) -> sym
flg
is given and
non-NIL
, the new symbol will be an external symbol.
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.
: (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
(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) -> flg
T
when the argument any
is a number.
: (num? 123)
-> T
: (num? (1 2 3))
-> NIL
(off sym ..) -> NIL
NIL
in the VAL
's of all argument symbols
sym
.
: (off A B)
-> NIL
: A
-> NIL
: B
-> NIL
(offset 'lst1 'lst2) -> cnt | NIL
cnt
position of the sublist 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
.
: (on A B)
-> T
: A
-> T
: B
-> T
(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
(or 'any ..) -> any
any
are evaluated from left to
right. If a non-NIL
value is encountered, it is returned
immediately. Else the result of the last expression is returned.
: (or (= 3 3) (read))
-> T
: (or (= 3 4) (read))
abc
-> abc
(out 'any . prg) -> any
any
as output channel during the execution of
prg
. The current output channel will be saved and restored
appropriately. If the argument is NIL
, standard output is used. If
the argument is a symbol, it is used as a file name (opened in "append" mode if
the first character is "+
"). If it is a number, it is used as the
descriptor of an open file. Otherwise (if it is a list), it is taken as a
command with arguments, and a pipe is opened for output. See also call
, in
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
T
when the argument any
is a list (a cons
pair cell).
: (pair NIL)
-> NIL
: (pair (1 . 2))
-> T
: (pair (1 2 3))
-> T
(pass 'foo ['any ..]) -> any
foo
all arguments any
, and all remaining
variable arguments (@
) as they would be returned by rest
. (pass 'foo 'any)
is equivalent to
(apply 'foo (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)
(pat? 'any) -> flg
T
when the argument any
is a symbol that
starts with an at-mark "@
".
: (pat? '@)
-> T
: (pat? "@Abc")
-> T
: (pat? "ABC")
-> NIL
: (pat? 123)
-> NIL
(peek) -> sym
char
would return.
$ cat a
# Comment
abcd
$ p
: (in "a" (list (peek) (char)))
-> ("#" "#")
(peer ['cnt]) -> sym
cnt
, or NIL
when not successful. If
cnt
is NIL
, the socket most recently connected by
listen
is used.
: (listen (port 4444))
-> 4
: (peer)
-> "localhost"
: (peer 4)
-> "localhost"
(pick 'foo 'lst ..) -> any
foo
to successive elements of lst
until
non-NIL
is returned. Returns that value, or NIL
if foo
did not return non-NIL
for any element of
lst
. When additional lst
arguments are given, their
elements are also passed to foo
. See also seek
, find
.
: (put 'D 'str "Hello")
-> "Hello"
: (pick '((X) (get X 'str)) '(A B C D E F))
-> "Hello"
(pool ['sym]) -> flg
sym
as a database file in read/write mode. If
the file does not exist, it is created. A currently open database is closed.
Returns T
when successful.
: (pool "/dev/hda2")
-> T
(pop 'var) -> any
CAR
) from the stack in
var
. See also cut
.
: (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
.
: (out "x" (pr 7 "abc" (1 2 3) 'a)) # Print to "x"
-> a
: # Exit Pico
$ hd x # Hexdump of "x"
00000000 04 0e 0e 61 62 63 01 04 02 04 04 04 06 03 05 61 ...abc.........a
00000010
(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
.
: (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
(prove 'lst ['lst]) -> lst
NIL
if not
successful. 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 ->
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.
: (putl 'X '((123 . a) flg ("Hello" . b)))
-> ((123 . a) flg ("Hello" . b))
: (get 'X 'a)
-> 123
: (get 'X 'b)
-> "Hello"
: (get 'X 'flg)
-> T
(quote . any) -> any
any
unevaluated. The reader recognizes the single quote
char '
as a macro for this function.
: '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]])
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) -> lst
lst
with a
maximal CAR
less than or equal to any
, or
NIL
if no match is found. lst
may be unsorted. 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)
(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 into
a single number. See also pr
.
: (in "/dev/urandom" (rd 20))
-> 396737673456823753584720194864200246115286686486
(read) -> any
NIL
is returned
upon end of file.
: (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))
(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) (+City)) # City
(rel str (+Key +List +Ref +String) Cit) # Street
(rel prs (+List +Joint) adr (+Person)) # Inhabitants
(class +City +Entity)
(rel nm (+Key +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
.
: (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 optional arguments, 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)
(run 'any) -> any
any
is an atom, run
behaves like
eval
. Otherwise any
is a list, which is evaluated in
sequence. The last result is returned.
: (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 'foo 'lst ..) -> lst
foo
to lst
and all successive
CDR
's, until non-NIL
is returned. Returns the
tail of lst
starting with that element, or NIL
if foo
did not return non-NIL
for any element of
lst
. When additional lst
arguments are given, they are
passed to foo
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.
: (stop> Dlg)
-> NIL
(seq 'sym1 ['sym2]) -> sym | 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 necessary.
: (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 sym 'any ..) -> any
any
in the sym
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 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
$ cat a
# Comment
abcd
$ p
: (in "a" (skip) (peek))
-> "a"
(sort 'lst) -> lst
lst
by destructively exchanging its elements. See also Comparing.
(space ['cnt]) -> T
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 'any1 'any2 ..) -> lst
lst
at all places containing an element
anyX
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
(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. The
second form does the reverse operation by building a string from a list.
: (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) -> flg
T
when the argument any
is a transient
symbol (string).
: (str? 123)
-> NIL
: (str? '{ABC})
-> NIL
: (str? 'abc)
-> NIL
: (str? "abc")
-> T
(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 'foo 'lst ..) -> num
foo
to each element of lst
. When
additional lst
arguments are given, their elements are also passed
to foo
. Returns the sum of all numeric values returned from
foo
.
: (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 (val X)) ) )
(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 the `+Dialog' class
(super) # Call the `stop>' method of the `+Form' superclass
(close> This) ) # then close the connection
(sym? 'any) -> flg
T
when the argument any
is a symbol.
: (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)
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 Pico Prolog (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.
: (with 'X (println 'This 'is This))
This is X
-> X
(t . prg) -> T
prg
, and returns T
. See also nil
, prog
, prog1
and prog2
.
: (t (println 'Ok))
Ok
-> T
(tail 'cnt 'lst) -> lst
cnt
elements of
lst
. See also head
.
: (tail 3 '(a b c d e f))
-> (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)
(tell 'any ['any ..]) -> any
(any 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.
: (call "ps x") # Show processes
PID TTY STAT TIME COMMAND
..
1321 pts/0 S 0:00 ./pico .. # Parent process
1324 pts/0 S 0:01 ./pico .. # First child
1325 pts/0 S 0:01 ./pico .. # 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). Local symbol bindings are restored, open files are closed and
internal data structures are reset appropriately, as the environment was at the
time when the corresponding catch
was called. Then any
is returned from that catch
.
: (de foo (N)
(println N)
(throw 'Ok) )
-> foo
: (let N 1 (catch 'Ok (foo 7)) (println N))
7
1
-> 1
(tick 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 'sym ['flg]) -> lst|sym
sym
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) -> tim
(time 'tim) -> (h m s)
(time 'h 'm ['s]) -> tim | NIL
(time '(h m [s])) -> tim | NIL
- Calculates the time of day, represented as the number of seconds since
midnight. When called without arguments, the current time 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
- When
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 'cnt) -> sym
- Inserts
$
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. For built-in Pico functions (a
C
-function pointer) the number of arguments cnt
must
be specified.
: (trace '+ 2) # Trace '+' with 2 arguments
-> +
: (+ 3 4)
+ : 3 4
+ = 7
-> 7
(trim 'lst) -> lst
- Returns a copy of
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)
(type 'any) -> lst
- Return the type (list of classes) of the object
sym
. See also
isa
.
: (type '{1A;3})
(+Address)
U
(unify 'any) -> lst
- Unifies
any
with the current Pico Prolog (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
- Conditional execution: When the condition
any
evaluates to
non-NIL
, NIL
is returned. Otherwise prg
is executed and the result returned.
: (unless (= 3 3) (println 'Strange 'result))
-> NIL
: (unless (= 3 4) (println 'Strange 'result))
Strange result
-> result
(until 'any . prg) -> any
- Conditional loop: While the condition
any
evaluates to
NIL
, prg
is repeatedly executed. If prg
is never executed, NIL
is returned. Otherwise the result of
prg
is returned.
: (until (=T (setq N (read)))
(println 'square (* N N)) )
4
square 16
9
square 81
T
-> 81
(upp? 'any) -> flg
- Returns
T
when the argument any
is a string
(symbol) that starts with an uppercase character.
: (upp? "A")
-> T
: (upp? "a")
-> NIL
: (upp? 123)
-> NIL
: (upp? ".")
-> NIL
(uppc 'any) -> any
- Upper case conversion: If
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.
: (uppc 123)
-> 123
: (uppc "abc")
-> "ABC"
: (uppc 'car)
-> "CAR"
(use sym . prg) -> any
(use (sym ..) . prg) -> any
- Defines local variables. The value of the symbol
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
V
(val 'var) -> any
- Returns the current value of
var
.
: (setq L '(a b c))
-> (a b c)
: (val 'L)
-> (a b c)
: (val (cdr L))
-> b
W
(wait ['cnt] . prg) -> any
- Waits for a condition. While the result of the execution of
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
-> 2000
: (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
- Conditional execution: When the condition
any
evaluates to
non-NIL
, prg
is executed and the result is returned.
Otherwise NIL
is returned.
: (when (> 4 3) (println 'Ok) (println 'Good))
Ok
Good
-> Good
(while 'any . prg) -> any
- Conditional loop: While the condition
any
evaluates to
non-NIL
, prg
is repeatedly executed. If
prg
is never executed, NIL
is returned. Otherwise the
result of prg
is returned.
: (while (read)
(println 'got: @) )
abc
got: abc
1234
got: 1234
NIL
-> 1234
(whilst 'any . prg) -> any
- Conditional loop: While the condition
any
evaluates to a list
(a pair or NIL
), prg
is repeatedly executed. If
prg
is never executed, NIL
is returned. Otherwise the
result of prg
is returned.
: (whilst (read) (println 'got: @))
(a b c)
got: (a b c)
NIL
got: NIL
abc
-> NIL
(wipe 'sym|lst) -> sym|lst
- Clears the
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". It is an error 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
- Saves the current object
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
.
: (put 'X 'a 1)
-> 1
: (put 'X 'b 2)
-> 2
: (with 'X (list (: a) (: b)))
-> (1 2)
X
(xchg 'var 'var ..) -> any
- Exchange the values of successive
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
- Returns T if exactly one of the arguments evaluates to non-
NIL
.
: (xor T NIL)
-> T
: (xor T T)
-> NIL
Y
Z
(zap 'sym) -> sym
- "Delete" the symbol
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.
: (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
- Stores
0
in the VAL
's of all argument symbols
sym
.
: (zero A B)
-> 0
: A
-> 0
: B
-> 0
Other
(! . prg) -> any
- Low level breakpoint function: The current execution environment is saved
and the I/O channels are redirected to the console. Then
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 ^
.
: (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
- Low level trace function: The first argument
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
- Returns the remainder from the divisions of successive
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
- Returns the bitwise
AND
of all num
arguments.
: (& 6 3)
-> 2
: (& 7 3 1)
-> 1
(* 'num ..) -> num
- Returns the product of all
num
arguments.
: (* 1 2 3)
-> 6
: (* 5 3 2 2)
-> 60
(*/ 'num 'num 'num ['flg]) -> num
- Returns the product of the first two
num
arguments, divided by
the third argument. If flg
is non-NIL
, the result is
rounded to the nearest integer value.
: (*/ 3 4 2)
-> 6
: (*/ 1234 2 10)
-> 246
: (*/ 1234 2 10 T)
-> 247
*Bye
- A global variable holding a (possibly empty)
prg
body, to be
executed just before the termination of the Pico interpreter.
: (push '*Bye '(call "rm -f *.tmp")) # Remove all temporary files
-> (call "rm -f *.tmp")
*Class
- A global variable holding the current class.
: (class +Test)
-> +Test
: *Class
-> +Test
*DB
- A global constant holding the external symbol
{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} (+ObjRoot)
nm (566 . {AhDx})
-> {P}
: (show '{3})
{3} (+ObjRoot)
tel (681376 . {Agyl})
nm (1461322 . {2gu7})
-> {3}
*Err
- A global variable holding a (possibly empty)
prg
body which
will be executed during error processing. See also Error
Handling
.
: (de *Err (prinl "Fatal error!") (bye))
-> ((prinl "Fatal error!") (bye))
: (/ 3 0)
!? (/ 3 0)
Div/0
Fatal error!
$
*Msg
- A global variable holding the last recently issued error message. See also
Error Handling
.
: (+ 'A 2)
!? (+ 'A 2)
A -- Number expected
?
:
: *Msg
-> "Number expected"
*Key
- This global variable can hold a list of
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 then input data are
available, or a timeout occurred.
: (de *Key (-2000 0 (println '2sec))) # Install 2-sec-timer
-> *Key
: 2sec # Prints "2sec" every 2 seconds
2sec
2sec
# (Enter) Exit
$
*Dbg
- A boolean variable controlling the
$
(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
*Led
- A global variable holding a (possibly empty)
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
*Pid
- A global constant holding the current process-id.
: *Pid
-> 6386
: (call "ps") # Show processes
PID TTY TIME CMD
.... ... ........ .....
6386 pts/1 00:00:00 pico # <- current process
6388 pts/1 00:00:00 ps
-> T
*Scl
- A global variable holding the current fixed-point input scale. See also
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)
(+ 'num ..) -> num
- Returns the sum of all
num
arguments.
: (+ 1 2 3)
-> 6
(- 'num ..) -> num
- Returns the difference of the first
num
argument and all
following arguments. If only a single argument is given, it is negated.
: (- 7)
-> -7
: (- 7 2 1)
-> 4
(/ 'num ..) -> num
- Returns the the first
num
argument successively divided by all
following arguments.
: (/ 12 3)
-> 4
: (/ 60 3 2 2)
(: sym [sym1|cnt .. sym2]) -> any
- Fetches a value
any
for a property key 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. Used typically in methods or with
bodies.
: (put 'X 'a 1)
-> 1
: (with 'X (: a))
-> 1
(:: sym [sym1|cnt .. sym2]) -> lst|sym
- Fetches a property for a property key
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.
: (with 'X (=: cnt 0) (inc (:: cnt)) (: cnt))
-> 1
(< 'any ..) -> flg
- Returns
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
- Returns
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
- Returns
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
- Returns
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) -> flg
- Returns
T
when any
is a number with value zero.
: (=0 (- 6 3 2 1))
-> T
: (=0 'a)
-> NIL
(=: sym [sym1|cnt .. sym2] 'any)
- Stores a new value
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.
: (with 'X (=: a 1) (=: b 2))
-> 2
: (get 'X 'a)
-> 1
: (get 'X 'b)
-> 2
(== 'any ..) -> flg
- Returns
T
when all any
arguments are the same
(pointer equality).
: (== 'a 'a)
-> T
: (== 'NIL NIL (val NIL) (car NIL) (cdr NIL))
-> T
: (== 6 (* 1 2 3))
-> NIL
(==== ['sym ..]) -> NIL
- Close the current transient scope by clearing the transient hash table. All
transient symbols become hidden and inaccessible by the reader. Then any
optional
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
- Returns
T
when any
is the symbol T
.
: (=T 0)
-> NIL
: (=T "T")
-> NIL
: (=T T)
-> T
(> 'any ..) -> flg
- Returns
T
when all arguments any
are in strictly
decreasing order. See also Comparing.
: (> 4 3)
-> T
: (> 'A 999)
-> T
(>= 'any ..) -> flg
- Returns
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
- Shifts right the
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
"?"
- Top-level function for Pico Prolog (Pilog) queries. It displays each result,
waits for console input, and terminates when a non-empty line is entered.
: (? (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
@
- Holds the result of the last top level expression in the current
read-eval-print loop, or the result of the conditional expression during the
evaluation of flow functions (see
@ Result
).
When @
is used as a formal parameter in lambda
expressions, it denotes a variable number of evaluated arguments.
@@
- Holds the result of the second last top level expression in the current
read-eval-print loop (see
@ Result
).
@@@
- Holds the result of the third last top level expression in the current
read-eval-print loop (see
@ Result
).
^
- Holds the currently executed expression during a breakpoint or an error. See
also
!
and e
.
: (* (+ 3 4) (/ 7 0))
!? (/ 7 0)
Div/0
? ^
-> (/ 7 0)
(| 'num ..) -> num
- Returns the bitwise
OR
of all num
arguments.
: (| 1 2)
-> 3
: (| 1 2 4 8)
-> 15