abu@software-lab.de

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)

The Pico Lisp Reference

(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.


Introduction

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

Simple
The internal data structure should be as simple as possible. Only one single data structure is used to build all higher level constructs.
Unlimited
There are no limits imposed upon the language due to limitations of the virtual machine architecture. That is, there is no upper bound in symbol name length, number digit counts, or data structure and buffer sizes, except for the total memory size of the host machine.
Dynamic
Behavior should be as dynamic as possible ("run"-time vs. "compile"-time). All decisions are delayed till runtime where possible. This involves matters like memory management, dynamic symbol binding, and late method binding.
Practical
Pico is not just a toy of theoretical value. Pico is used since 1988 in actual application development, research and production.


The Pico Machine

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 Cell

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).


Data Types

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


Numbers

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.


Symbols

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

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:

These requirements are fulfilled by the above structure.


Internal Symbols

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

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

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

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.


Lists

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).


Memory Management

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.


Programming Environment

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.


Invocation

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 loaded 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.


Input/Output

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:


Numbers

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"


Symbols

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.


NIL

Besides for standard normal form, NIL is also recognized as (), [], "" or {}.


: NIL
-> NIL
: ()
-> NIL
: ""
-> NIL

Output will always be as NIL.


Internal Symbols

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.


Transient Symbols

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 loading a source file, or it can be reset explicitly with the ==== function. With that mechanism, it is possible to create symbols with a local access scope, not accessible from other parts of the program.

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 Symbols

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

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

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))))


Evaluation

Pico tries to evaluate any expression encountered in the read-eval-print loop. Basically, it does so by applying the following 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

either
a number. When a number is used as a function, it is simply taken as a pointer to executable code that will be called with the list of (unevaluated) arguments as its single parameter. It is up to that code to evaluate the arguments, or not. Some functions do not evaluate their arguments (e.g. quote) or evaluate only some of their arguments (e.g. setq).
or
a lambda expression. A lambda expression is a list, whose 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:

When the CAR is a list of symbols
For each of these symols an argument is evaluated, then the symbols are bound simultaneously to the results. The body of the lambda expression is executed, then the 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.
Otherwise, when the CAR is the symbol @
All arguments are evaluated and the results kept internally in a list. The body of the lambda expression is executed, and the evaluated arguments can be accessed sequentially with the args, next, arg and rest functions. This allows to define functions with a variable number of evaluated arguments.
Otherwise, when the CAR is a single symbol
The symbol is bound to the whole unevaluated argument list. The body of the lambda expression is executed, then the symol is restored to its original value. This allows to define functions with unevaluated arguments. Any kind of interpretation and evaluation of the argument list can be done inside the expression body.

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


Error Handling

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
:


@ Result

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
In read-eval loops, the last three results which were printed at the console are available in @@@, @@ and @, in that order (i.e the latest result is in @.


: (+ 1 2 3)
-> 6
: (/ 128 4)
-> 32
: (- @ @@)        # Subtract the last two results
-> 26

Flow functions
Flow functions store the result of evaluating their conditional expression in @.


: (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.


Comparing

In Pico, it is legal to compare data items of arbitrary type. Any two items are either

Identical
They are the same memory object (pointer equality). For example, two internal symbols with the same name are identical.
Equal
They are equal in every respect (structure equality), but need not to be identical. Examples are numbers with the same value, symbols with the same name or lists with equal elements.
Or they have a well-defined ordinal relationship
Numbers are comparable by their numeric value, strings by their name, and lists recursively by their elements (if the 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)


OO Concepts

Pico comes with built-in object oriented extensions. There seems to be a common aggreement upon three criteria for object orientation:

Encapsulation
Code and data are encapsulated into objects, giving them both a behavior and a state. Objects communicate by sending and receiving messages.
Inheritance
Objects are organized into classes. The behavior of an object is inherited from its class(es) and superclass(es).
Polymorphism
Objects of different classes may behave differently in response to the same message. For that, classes may define different methods for each message.

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 =:.


Database

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


Naming Conventions

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:

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.


Breaking Traditions

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:

Case Sensitivity
Pico Lisp distinguishes between upper case and lower case characters in symbol names. Thus, CAR and car are different symbols, which was not the case in traditional Lisp systems.
QUOTE
In traditional Lisp, the QUOTE function returns its first unevaluated argument. In Pico Lisp, on the other hand, quote returns the whole unevaluated argument list.
LAMBDA
The LAMBDA function, in some way at the heart of traditional Lisp, is completely missing (and quote is used instead).
PROG
The 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).
Function/Value
In Pico Lisp, a symbol cannot have a value and a function definition at the same time. Though this is a disadvantage at first sight, it allows a completely uniform handling of functional data.


Function Reference

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:

Other (derived) data types

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

Symbol Functions
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
Property Access
put get prop =: : :: putl getl wipe meta
Predicates
atom pair lst? num? sym? sp? pat? fun? str? ext? == n== = <> =0 =T n0 nT < <= > >= match prove -> unify
Arithmetics
+ - * / % */ inc dec >> lt0 gt0 abs bit? & | sqrt seed rand max min length size format
List Processing
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
Control Flow
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
Mapping
apply pass all maps map mapc maplist mapcar mapcon mapcan filter seek find pick cnt sum maxi mini
Input/Output
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
Database
pool begin commit rollback lock seq mark dbck rel
Debugging
stat debug trace
System Functions
argv gc heap env stk stat date time stamp cd ctty info call tick kill quit fork bye
Globals
NIL *DB ^ @ @@ @@@ This T *Pid *Scl *Class *Key *Dbg *Led *Err *Msg *Bye


A

(abs 'num) -> num
Returns the absolute value of the num argument.


: (abs -7)
-> 7
: (abs 7)
-> 7

(all 'foo) -> any
Applies 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
Logical AND. The expressions 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
Appends all argument lists.


: (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
Applies 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
Can only be used inside functions with a variable number of arguments (with @). 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
Can only be used inside functions with a variable number of arguments (with @). 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
Returns a list of strings containing all remaining command line arguments. A hyphen "-" can be used to stop loading further arguments.


$ ./p -"println 'Ok" - abc 123
Ok
: (argv)
-> ("abc" "123")

(asoq 'any 'lst) -> lst
Searches an association list. Returns the first element from 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
Searches an association list. Returns the first element from 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
Increments 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
Returns 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


B

(begin) -> T
Opens a nested transaction. Not needed for normal single-level transaction processing with 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
Binds value(s) to symbol(s). The first argument 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
Returns 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
Returns 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
Creates and returns a new anonymous symbol. The initial value is set to the any argument.


: (show (box '(A B C)))
$134425627 (A B C)
-> $134425627

(bye 'cnt|NIL)
Executes the 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
$


C

(caaar 'lst) -> any
List access shortcut: Equivalent to (car (car (car 'lst))).


: (caaar '(((1 2) 3) 4))
-> 1

(caadr 'lst) -> any
List access shortcut: Equivalent to (car (car (cdr 'lst))).


: (caadr '(1 (2 3)))
-> 2

(caar 'lst) -> any
List access shortcut: Equivalent to (car (car 'lst)).


: (caar '((1 2) (3 4)))
-> 1

(cadar 'lst) -> any
List access shortcut: Equivalent to (car (cdr (car 'lst))).


: (cadar '((1 2 3)))
-> 2

(cadddr 'lst) -> any
List access shortcut: Equivalent to (car (cdr (cdr (cdr 'lst)))), or the fourth element of lst.


: (cadddr (1 2 3 4 5 6))
-> 4

(caddr 'lst) -> any
List access shortcut: Equivalent to (car (cdr (cdr 'lst))), or the third element of lst.


: (caddr (1 2 3 4 5 6))
-> 3

(cadr 'lst) -> any
List access shortcut: Equivalent to (car (cdr 'lst)), or the second element of lst.


: (cadr (1 2 3 4 5 6))
-> 2

(call 'any ..) -> flg
Calls an external system command. The 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
List access: Returns the first element of lst.


: (car (1 2 3 4 5 6))
-> 1

(case 'any (any1 . prg1) (any2 . prg2) ..) -> any
Multi-way branch: 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
Sets up the environment for a non-local jump with 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
Changes the current directory to 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
List access shortcut: Equivalent to (cdr (car (car 'lst))).


: (cdaar '(((1 2 3))))
-> (2 3)

(cdadr 'lst) -> any
List access shortcut: Equivalent to (cdr (car (cdr 'lst))).


: (cdadr '((1 2) (3 4)))
-> (4)

(cdar 'lst) -> any
List access shortcut: Equivalent to (cdr (car 'lst)).


: (cdar '((1 2) (3 4)))
-> (2)

(cddar 'lst) -> any
List access shortcut: Equivalent to (cdr (cdr (car 'lst))).


: (cddar '((1 2 3 4)))
-> (3 4)

(cddddr 'lst) -> any
List access shortcut: Equivalent to (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
List access shortcut: Equivalent to (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
List access shortcut: Equivalent to (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
List access: Returns all but the first element of lst.


: (cdr (1 2 3 4 5 6))
-> (2 3 4 5 6)

(chain 'lst ..) -> lst
Concatinates (destructively) one or several new list elements 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
When called without arguments, the next character from the current input stream is returned as a single-character transient symbol, or 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
Returns the name of 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
Produces a circular list by (destructively) connecting 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
Returns a copy of 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
Closes a file descriptor cnt. See also open, listen, connect.


: (close 2)                            # Close standard error
-> T

(cnt 'foo 'lst ..) -> cnt
Applies 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
Closes a transaction, by writing all new or modified external symbols to the database, and by removing all deleted symbols from the database. For nested transactions, only the changes since the last call to 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
Connects 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
Concatenates all argument lists (destructively).


: (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
Multi-way conditional: If any of the 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
Tries to establish a TCP/IP connection to a server listening at host 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
Constructs a new list cell with the first argument in the 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
Copies the argument 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
Changes the current TTY device to sym.


: (ctty "/dev/tty")
-> T

(cut 'cnt 'var) -> lst
Pops the first 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)


D

(date) -> dat
(date 'dat) -> (y m d)
(date 'y 'm 'd) -> dat | NIL
(date '(y m d)) -> dat | NIL
Calculates a calendar date, represented as the number of days since first of march in the year 0. When called without arguments, the current date is returned. When called with a single number dat, it is taken as a date and a list with the corresponding year, month and day is returned. When called with three numers (or a list of three numbers) for the year, month and day, the corresponding date is returned (or NIL if they do not represent a legal date). See also time.


: (date)                         # Today
-> 730589
: (date 2000 6 12)               # 12-06-2000
-> 730589
: (date 2000 22 5)               # Illegal date
-> NIL
: (date (date))                  # Today's year, month and day
-> (2000 6 12)
: (- (date) (date 2000 1 1))     # Number of days since first of January
-> 163

(dbck) -> sym | NIL
Performs a low-level integrity check of the current database file, and returns 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
Assigns a definition to the 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
Inserts a ! 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
Decrements the 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
The first form assigns a definition to the first 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
Stores new values 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
Deletes 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
Deletes 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
Defines a method for the message 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
Counted loop with conditional exit: The body is executed at most 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

(e . prg) -> any
Used in a breakpoint. Evaluates 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
Reads the current input channel, and writes to the current output channel. If 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
Return a list of all dynamically bound symbols. See also 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
Evaluates 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
Returns T when the argument any is an external symbol.


: (ext? 123)
-> NIL
: (ext? 'abc)
-> NIL
: (ext? "abc")
-> NIL
: (ext? '{ABC})
-> T

(extern 'sym) -> sym
Converts a transient symbol to an external symbol. If the symbol is already extern, it is returned as it is. Otherwise, it is inserted into the external hash table. See also intern and ====.


: (extern "A1b3")
-> {A1b3}

(extra ['any ..]) -> any
Can only be used inside methods. Sends the current message to the current object 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


F

(fill 'any) -> any
Fills a pattern 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
Applies 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
Applies 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
Flushes the current output stream by writing all buffered data. A call to 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
Conditional loop with local variable: The value of 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
Forks a child process. Returns 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
Converts a number 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
Skips the current input channel until one of the patterns 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
Returns 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


G

(gc ['cnt]) -> cnt | NIL
Forces a garbage collection. When 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
Fetches a value 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
Fetches the complete property list 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
Returns T when the num argument is greater than zero.


: (gt0 -2)
-> NIL
: (gt0 3)
-> T


H

(head 'cnt 'lst) -> lst
Returns a new list made of the first 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
Returns the number of free cells currently available (if 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
Uses the file descriptor 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"


I

(if 'any1 'any2 . prg) -> any
Conditional execution: If the condition 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
Conditional execution ("If not"): If the condition 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
Opens 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
Increments the 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
Returns the 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)
Returns information about a file with the name 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
Converts a transient symbol to an internal symbol. If the symbol is already intern, it is returned as it is. Otherwise, it is inserted into the internal hash table. See also extern and ====.


: (intern "abc")
-> abc
: (intern 'car)
-> car
: ((intern (pack "c" "a" "r")) (1 2 3))
-> 1

(isa 'cls|typ 'any) -> flg
Returns T when any is an object that inherits from cls or type. See also type.


: (isa '+Address Obj)
-> T
: (isa '(+Male +Person) Obj)
-> NIL


J

(job lst . prg) -> any
Executes a job within its own environment (as specified by symbol-values-pairs in 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


K

(key ['cnt]) -> sym
Returns the next character from standard input as a single-character transient symbol. The console is set to raw mode. While waiting for a key press, a 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
Sends a signal with the signal number 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


L

(last 'lst) -> any
Returns the last element of lst.


: (last (1 2 3 4))
-> 4
: (last '((a b) c (d e f)))
-> (d e f)

(length 'any) -> cnt | T
Returns the "length" of 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
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 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
Reads a line of characters from the current input channel. End of line is recognized either as return (hex "0D"), as linefeed (hex "0A"), or as a return-linefeed sequence (hex "0D0A"). If 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
Returns the number of lines in a file with the name sym. See also info.


: (lines "x.l")
-> 11

(link 'any ..) -> any
Links one or several new elements 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
Returns a list of all any arguments.


: (list 1 2 3 4)
-> (1 2 3 4)
: (list 'a (2 3) "Ok")
-> (a (2 3) "Ok")

(lst? 'any) -> flg
Returns 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
Listens a socket descriptor 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
Loads all 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
Write-locks an external symbol 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
Searches for the current value of the pattern variable 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
Returns 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
Lower 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 lower case, is returned.


: (lowc 123)
-> 123
: (lowc "ABC")
-> "abc"

(lt0 'num) -> flg
Returns T when the num argument is less than zero.


: (lt0 -2)
-> T
: (lt0 3)
-> NIL


M

(made ['lst1 ['lst2]]) -> lst
Set a new initial list value for the current 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
Initializes and executes a list-building process with the 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
Applies 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
Applies 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
Applies 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
Applies 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
Applies 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
Applies 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
Applies 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
Test, set or reset a mark for 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
Takes the first 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
Returns the largest of all any arguments. See also Comparing.


: (max 2 'a 'z 9)
-> z
: (max (5) (2 3) 'X)
-> (5)

(maxi 'foo 'lst ..) -> any
Applies 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
Returns the tail of 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
Returns the tail of 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
Fetches a property value 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
This function is usually not called directly, but is used by 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
Returns the function body of the method that would be executed upon sending the message 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
Returns the smallest of all any arguments. See also Comparing.



: (min 2 'a 'z 9)
-> 2
: (min (5) (2 3) 'X)
-> X

(mini 'foo 'lst ..) -> any
Applies 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
Builds a list from the elements of the argument 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
Returns the tail of the second argument 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

(n== 'any ..) -> flg
Returns 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
Returns 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
Returns T when any is not the symbol T. See also =T.


: (nT 0)
-> T
: (nT "T")
-> T
: (nT T)
-> NIL

(nand 'any ..) -> flg
Logical NAND. The expressions 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
Produces a list of at least 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
Creates and returns a new symbol. If 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
Can only be used inside functions with a variable number of arguments (with @). 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
Executes prg, and returns NIL. See also t, prog, prog1 and prog2.


: (nil (println 'Ok))
Ok
-> NIL

(nor 'any ..) -> flg
Logical NOR. The expressions 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
Logical negation. Returns T if any evaluates to NIL.


: (not (== 'a 'a))
-> NIL
: (not (get 'a 'a))
-> T

(nth 'lst 'cnt ..) -> lst
Returns the tail of 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
Returns T when the argument any is a number.


: (num? 123)
-> T
: (num? (1 2 3))
-> NIL


O

(off sym ..) -> NIL
Stores NIL in the VAL's of all argument symbols sym.


: (off A B)
-> NIL
: A
-> NIL
: B
-> NIL

(offset 'lst1 'lst2) -> cnt | NIL
Returns the 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
Stores T in the VAL's of all argument symbols sym.


: (on A B)
-> T
: A
-> T
: B
-> T

(open 'sym) -> cnt | NIL
Opens the file 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
Logical OR. The expressions 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
Opens 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


P

(pack 'any ..) -> sym
Returns a transient symbol whose name is concatenated from all arguments 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
Returns 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
Passes to 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
Returns 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
Single character look-ahead: Returns the same character as the next call to char would return.


$ cat a
# Comment
abcd
$ p
: (in "a" (list (peek) (char)))
-> ("#" "#")

(peer ['cnt]) -> sym
Returns the name (or the address) of the peer connected to the socket descriptor 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
Applies 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
Opens the file 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
Pops the first element (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
Opens a TCP/IP-Port 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
Binary print: Prints all 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
Returns non-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
Prints the string representation of all 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
Prints the string representation of all 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
Prints all 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
Prints all 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
Prints all 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
Executes 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
Executes all arguments, and returns the result of the first expression any1. See also nil, t, prog and prog2.


: (prog1 (print 1) (print 2) (print 3))
123-> 1

(prog2 'any1 'any2 . prg) -> any2
Executes all arguments, and returns the result of the second expression 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
Fetches a property for a property key 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
The Pico Prolog (Pilog) interpreter. Tries to prove the query list in the first argument and returns the modified query, or 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
Implements a stack using a list in 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
Stores a new value 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
Stores a complete new property list 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


Q

(quote . any) -> any
Returns 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
Implements a queue using a list in 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]])
Stops current execution. If no arguments are given, control is returned to the top level read-eval-print loop. Otherwise, an error handler is entered. The first argument can be some error message, and the second might be the reason for the error. See also Error Handling.


: (de foo (X) (quit "Sorry, my error" X))
-> foo
: (foo 123)                                  # `X' is bound to `123'
123 -- Sorry, my error                       # Error entered
? X                                          # Inspect `X'
-> 123
?                                            # Empty line: Exit
:


R

(rand ['cnt1 'cnt2] | ['T]) -> cnt | flg
Returns a pseudo random number in the range cnt1 .. cnt2 (or -2147483648 .. +2147483647 if no arguments are given). If the argument is T, a boolean value flg is returned. See also seed.


: (rand 3 9)
-> 3
: (rand 3 9)
-> 7

(rank 'any 'lst) -> lst
Searches a ranking list. Returns the element from 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
Binary read: Reads one item from the current input channel in encoded binary format. When called with a 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
Reads one item from the current input channel. 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
Defines a relation 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
Replaces in 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
Can only be used inside functions with a variable number of arguments (with @). 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
Returns a reversed copy of lst.


: (reverse (1 2 3 4))
-> (4 3 2 1)

(rewind) -> flg
Sets the file position indicator for the current output stream to the beginning of the file, and truncates the file length to zero. Returns T when successful. See also flush.


(rollback) -> flg
Cancels a transaction, by discarding all modifications of external symbols. For nested transactions, only the changes since the last call to 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
Rotate: The contents of the cells of 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
If 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


S

(seed 'any) -> cnt
Initializes the random generator's seed, and returns a pseudo random number in the range -2147483648 .. +2147483647. See also rand.


: (seed "init string")
-> 2015582081
: (rand)
-> -706917003
: (rand)
-> 1224196082
: (seed "init string")
-> 2015582081
: (rand)
-> -706917003
: (rand)
-> 1224196082

(seek 'foo 'lst ..) -> lst
Applies 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
Sends the message 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
Sequential single step: Returns the next external symbol following sym1 in the database, or NIL when the end of the database is reached. When sym2 is given, the database is extended up to (including the creation of) sym2 if necessary.


: (pool "db")
-> T
: (seq *DB)
-> {2}
: (seq @)
-> {3}

(set 'var 'any ..) -> any
Stores new values any in the var arguments.


: (set 'L '(a b c)  (cdr L) '999)
-> 999
: L
-> (a 999 c)

(setq sym 'any ..) -> any
Stores new values 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
Returns the "size" of 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
Skips all white space and comments in the input stream.


$ cat a
# Comment
abcd
$ p
: (in "a" (skip) (peek))
-> "a"

(sort 'lst) -> lst
Sorts lst by destructively exchanging its elements. See also Comparing.


(space ['cnt]) -> T
Prints cnt spaces, or a single space when cnt is not given.


: (space)
 -> T
: (space 1)
 -> T
: (space 2)
  -> T

(sp? 'any) -> flg
Returns 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
Splits 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
Returns the square root of the num argument.


: (sqrt 64)
-> 8
: (sqrt 1000)
-> 31
: (sqrt 10000000000000000000000000000000000000000)
-> 100000000000000000000

(stk any ..) -> T
Displays a dump of the internal runtime stack. All (unevaluated) 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
Returns a date-time string in the form "YYYY-MM-DD HH:MM:SS". If 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
Prints memory usage statistics. The total size of the heap (in megabytes), followed by the percentage of used cells. Returns the number of currently free cells. See also heap.


: (stat)
0.6 32%
-> 264813

(str 'sym) -> lst
(str 'lst) -> sym
In the first form, the string 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
Strips all leading quote symbols from any.


: (strip 123)
-> 123
: (strip '''(a))
-> (a)
: (strip (quote quote a b c))
-> (a b c)

(str? 'any) -> flg
Returns 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
Returns non-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
Applies 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
Can only be used inside methods. Sends the current message to the current object 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
Returns T when the argument any is a symbol.


: (sym? 'a)
-> T
: (sym? NIL)
-> T
: (sym? 123)
-> NIL
: (sym? '(a b))
-> NIL

(sync) -> flg
Waits for pending data from all family processes. While other processes are still sending data (via the 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
A global constant, evaluating to itself. 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
Holds the current object during method execution (see OO Concepts), or inside the body of a with statement.


: (with 'X (println 'This 'is This))
This is X
-> X

(t . prg) -> T
Executes prg, and returns T. See also nil, prog, prog1 and prog2.


: (t (println 'Ok))
Ok
-> T

(tail 'cnt 'lst) -> lst
Returns a new list made of the last 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
Inter-Family communication: Send an executable list (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)
Non-local jump into a previous 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
Executes 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
Reads from the current input channel till a character contained in 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