A global variable holding the target CPU (architecture). Typical values are "aarch64", "x86-64" etc. See also *OS and version.
: *CPU
-> "x86-64"
A global variable holding the current class. See also OO Concepts, class, extend, dm and var and rel.
: (class +Test)
-> +Test
: *Class
-> +Test
(cache 'var 'any [. prg]) -> any
Speeds up some calculations by maintaining a tree of previously calculated results in an idx structure ("memoization") in var. A hash of the argument any is used internally to build the index key. If no prg is given, the internal var holding a previously stored value is returned (note that var may have a name which is not human-readable).
: (de fibonacci (N)
   (cache '(NIL) N
      (if (>= 2 N)
         (+ (fibonacci (dec N)) (fibonacci (- N 2))) ) ) )
-> fibonacci

: (fibonacci 22)
-> 17711

: (fibonacci 10000)
-> 3364476487643178326662161200510754331030 ...  # (2090 digits)
: (off C)
-> NIL
: (cache 'C 1234 (* 3 4))
-> 12
: (inc (cache 'C 1234))
-> 13
: (val (cache 'C 1234))
-> 13
(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. The (system dependent) exit status code of the child process is stored in the global variable @@. See also exec.
: (when (call 'test "-r" "file.l")  # Test if file exists and is readable
   (load "file.l")  # Load it
   (call 'rm "file.l") )  # Remove it

: (cons (call "sh" "-c" "kill -SEGV $$") @@ (hex @@))
-> (NIL 11 . "B")
Pilog predicate that succeeds if the argument term can be proven.
: (be mapcar (@ NIL NIL))
-> mapcar
: (be mapcar (@P (@X . @L) (@Y . @M))
   (call @P @X @Y)                        # Call the given predicate
   (mapcar @P @L @M) )
-> mapcar
: (? (mapcar permute ((a b c) (d e f)) @X))
 @X=((a b c) (d e f))
 @X=((a b c) (d f e))
 @X=((a b c) (e d f))
 @X=((a c b) (d e f))
 @X=((a c b) (d f e))
 @X=((a c b) (e d f))
(can 'msg) -> lst
(Debug mode only) Returns a list of all classes that accept the message msg. See also OO Concepts, class, has, dep, what and who.
: (can 'zap>)
-> ((zap> . +relation) (zap> . +Blob) (zap> . +Entity))
: (more @ pp)
(dm (zap> . +relation) (Obj Val))

(dm (zap> . +Blob) (Obj Val)
      (call 'rm "-f" (blob Obj (: var))) ) )

(dm (zap> . +Entity) NIL
   (for X (getl This)
      (let V (or (atom X) (pop 'X))
         (and (meta This X) (zap> @ This V)) ) ) )

-> NIL
(car 'var) -> any
List access: Returns the value of var if it is a symbol, or the first element if it is a list. See also cdr and c..r.
: (car (1 2 3 4 5 6))
-> 1
(c[ad]*ar 'var) -> any
(c[ad]*dr 'lst) -> any
List access shortcuts. Combinations of the car and cdr functions, with up to four letters 'a' and 'd'.
: (cdar '((1 . 2) . 3))
-> 2
(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, prgN is executed, and the result returned. Otherwise NIL is returned. See also casq and state .
: (case (char 66) ("A" (+ 1 2 3)) (("B" "C") "Bambi") ("D" (* 1 2 3)))
-> "Bambi"
: (case 'b (a 1) ("b" 2) (b 3) (c 4))
-> 2
(casq 'any (any1 . prg1) (any2 . prg2) ..) -> any
Multi-way branch: any is evaluated and compared to the CAR elements anyN of each clause. == is used for comparison (pointer equality). If one of them is a list, any is in turn compared to all elements of that list. T is a catch-all for any value. If a comparison succeeds, prgN is executed, and the result returned. Otherwise NIL is returned. See also case and state.
: (casq 'b (a 1) ("b" 2) (b 3) (c 4))
-> 3
: (casq 'b (a 1) ("b" 2) ((a b c) 3) (c 4))
-> 3
(catch 'any . prg) -> any
Sets up the environment for a non-local jump which may be caused by throw or by a runtime error. If any is an atom, it is used by throw as a jump label (with T being a catch-all for any label), and a throw called during the execution of prg will immediately return the thrown value. Otherwise, any should be a list of strings, to catch any error whose message contains one of these strings, and catch will immediately return the matching string. If neither throw nor an error occurred, the result of prg is returned. The global variable @@ is set to T if a throw or error occurred, otherwise NIL. See also finally, quit and Error Handling.
: (catch 'OK (println 1) (throw 'OK 999) (println 2))
-> 999
: (catch '("No such file") (in "doesntExist" (foo)))
-> "No such file"
(cd 'any) -> sym
Changes the current directory to any. The old directory is returned on success, otherwise NIL. See also chdir, dir and pwd.
: (when (cd "lib")
   (println (length (dir)))
   (cd @) )
(cdr 'lst) -> any
List access: Returns all but the first element of lst. See also car and c..r.
: (cdr (1 2 3 4 5 6))
-> (2 3 4 5 6)
(center 'cnt|lst 'any ..) -> sym
Returns a transient symbol with all any arguments packed in a centered format. Trailing blanks are omitted. See also align, tab and wrap.
: (center 4 12)
-> " 12"
: (center 4 "a")
-> " a"
: (center 7 "a")
-> "   a"
: (center (3 3 3) "a" "b" "c")
-> " a  b  c"
(chain 'any ..) -> any
Concatenates (destructively) one or several new list 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 result list is maintained. chain returns the last linked argument. See also link, yoke 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 UTF-8 character (used as a top value in comparisons). Otherwise, when called with a symbol sym, the numeric unicode value of the first character of the name of that symbol is returned. See also peek, skip, key, line, till and eof.
: (char)                   # Read character from console
A                          # (typed 'A' and a space/return)
-> "A"
: (char 100)               # Convert unicode to symbol
-> "d"
: (char "d")               # Convert symbol to unicode
-> 100

: (char T)                 # Special case
-> # (not printable)

: (char 0)
-> NIL
: (char NIL)
-> 0
(chdir 'any . prg) -> any
Changes the current directory to any with cd during the execution of prg. Then the previous directory will be restored and the result of prg returned. See also dir and pwd.
: (pwd)
-> "/usr/abu/pico"
: (chdir "src" (pwd))
-> "/usr/abu/pico/src"
: (pwd)
-> "/usr/abu/pico"
(chkTree 'sym ['fun]) -> num
Checks a database tree node (and recursively all sub-nodes) for consistency. Returns the total number of nodes checked. Optionally, fun is called with the key and value of each node, and should return NIL for failure. See also tree and root.
: (show *DB '+Item)
{40} 6
   nr (6 . {H1})
   pr (6 . {H3})
   sup (6 . {H2})
   nm (67 . {I3})
-> {40}
: (chkTree '{H1})   # Check that node
-> 6
(chop 'any) -> lst
Returns any as a list of single-character strings. If any is NIL or a symbol with no name, NIL is returned. A list argument is returned unchanged.
: (chop 'car)
-> ("c" "a" "r")
: (chop "Hello")
-> ("H" "e" "l" "l" "o")
(circ 'any ..) -> lst
Produces a circular list of all any arguments by consing them to a list and then connecting the CDR of the last cell to the first cell. See also circ? and list.
: (circ 'a 'b 'c)
-> (a b c .)
(circ? 'any) -> any
Returns the circular list tail if any is a circular list, else NIL. See also circ.
: (circ? 'a)
-> NIL
: (circ? (1 2 3))
-> NIL
: (circ? (1 . (2 3 .)))
-> (2 3 .)
(class sym . typ) -> obj
Defines sym as a class with the superclass(es) typ. As a side effect, the global variable *Class is set to obj. See also extend, dm, var, rel, type, isa and object.
: (class +A +B +C +D)
-> +A
: +A
-> (+B +C +D)
: (dm foo> (X) (bar X))
-> foo>
: +A
-> ((foo> (X) (bar X)) +B +C +D)
(clause '(sym . any)) -> sym
Declares a Pilog fact or rule for the sym argument, by concatenating the any argument to the T property of sym. See also *Rule and be.
: (clause '(likes (John Mary)))
-> likes
: (clause '(likes (John @X) (likes @X wine) (likes @X food)))
-> likes
: (? (likes @X @Y))
 @X=John @Y=Mary
-> NIL
Pilog predicate that succeeds if the first argument is a predicate which has the second argument defined as a clause.
: (? (clause append ((NIL @X @X))))
-> T

: (? (clause append @C))
 @C=((NIL @X @X))
 @C=(((@A . @X) @Y (@A . @Z)) (append @X @Y @Z))
-> NIL
(clip 'lst) -> lst
Returns a copy of lst with all whitespace 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) -> cnt | NIL
Closes a file descriptor cnt, and returns it when successful. Should not be called inside an out body for that descriptor. See also open, poll, listen and connect.
: (close 2)                            # Close standard error
-> 2
(cmd ['any]) -> sym
When called without an argument, the name of the command that invoked the picolisp interpreter is returned. Otherwise, the command name is set to any. Setting the name may not work on some operating systems. Note that the new name must not be longer than the original one. See also argv, file and Invocation.
$ pil +
: (cmd)
-> "/usr/bin/picolisp"
: (cmd "!/bin/picolust")
-> "!/bin/picolust"
: (cmd)
-> "!/bin/picolust"
(cnt 'fun 'lst ..) -> cnt
Applies fun to each element of lst. When additional lst arguments are given, their elements are also passed to fun. Returns the count of non-NIL values returned from fun.
: (cnt cdr '((1 . T) (2) (3 4) (5)))
-> 2
(collect 'sym 'cls ['hook] ['any|beg ['end [sym|cnt ..]]])
Returns a list of all database objects of class cls, where the values for the sym arguments correspond to the any arguments, or where the values for the sym arguments are in the range beg .. end. sym, cls and hook should specify a tree for cls or one of its superclasses. If additional sym|cnt arguments are given, the final values for the result list are obtained by applying the get algorithm. See also db, aux, fetch, init, step and and search.
: (collect 'nr '+Item)
-> ({B1} {B2} {B3} {B4} {B5} {B6} {B8})
: (collect 'nr '+Item 3 6 'nr)
-> (3 4 5 6)
: (collect 'nr '+Item 3 6 'nm)
-> ("Auxiliary Construction" "Enhancement Additive" "Metal Fittings" "Gadget Appliance")
: (collect 'nm '+Item "Main Part")
-> ({B1})
(commit ['any] [exe1] [exe2]) -> T
Closes a transaction, by writing all new or modified external symbols to, and removing all deleted external symbols from the database. When any is given, it is implicitly sent (with all modified objects) via the tell mechanism to all family members. If exe1 or exe2 are given, they are executed as pre- or post-expressions while the database is locked and protected. 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. See also set and conc.
: (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). See also append and con.
: (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, prgN is executed and the result returned. Otherwise (all conditions evaluate to NIL), NIL is returned. See also nond, if, and, if2 and when.
: (cond
   ((= 3 4) (println 1))
   ((= 3 3) (println 2))
   (T (println 3)) )
-> 2
(connect 'any1 'any2) -> cnt | NIL
Tries to establish a TCP/IP connection to a server listening at host any1, port any2. any1 may be either a hostname or a standard internet address in numbers-and-dots/colons notation (IPv4/IPv6). any2 may be either a port number or a service name. Returns a socket descriptor cnt, or NIL if the connection cannot be established. See also listen and udp.
: (connect "localhost" 4444)
-> 3
: (connect "some.host.org" "http")
-> 4
(cons 'any ['any ..]) -> lst
Constructs a new list cell with the first argument in the CAR and the second argument in the CDR. If more than two arguments are given, a corresponding chain of cells is built. (cons 'a 'b 'c 'd) is equivalent to (cons 'a (cons 'b (cons 'c 'd))). See also list.
: (cons 1 2)
-> (1 . 2)
: (cons 'a '(b c d))
-> (a b c d)
: (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
(co ['any [. prg]]) -> any
Starts, resumes or stops a coroutine with the tag given by any. If called without arguments, the tag of the currently running coroutine is returned. If prg is not given, a coroutine with that tag will be stopped. Otherwise, if a coroutine running with that tag is found (pointer equality is used for comparison), its execution is resumed. Else a new coroutine with that tag is initialized and started. prg will be executed until it either terminates normally, or until yield is called. In the latter case co returns, or transfers control to some other, already running, coroutine. A coroutine cannot call or stop itself directly or indirectly. See also stack, catch and throw.
: (de pythag (N)   # A generator function
   (if (=T N)
      (co 'rt)  # Stop
      (co 'rt
         (for X N
            (for Y (range X N)
               (for Z (range Y N)
                  (when (= (+ (* X X) (* Y Y)) (* Z Z))
                     (yield (list X Y Z)) ) ) ) ) ) ) )

: (pythag 20)
-> (3 4 5)
: (pythag 20)
-> (5 12 13)
: (pythag 20)
-> (6 8 10)

(count 'tree) -> num
Returns the number of nodes in a database tree. See also tree and root.
: (count (tree 'nr '+Item))
-> 7
(create 'typ 'sym 'lst . prg)
Creates or updates database objects of the type typ with the properties in sym and lst. It handles large amounts of data, by sorting and traversing each database index separately. prg is executed repeatedly - and should return a list of values for the properties in sym and lst - until it returns NIL. If the fin of the list is NIL, a new object of type typ is created, otherwise it should be an existing object to be updated. If sym is non-NIL, the first column of the input data is assigned to the sym property and should already be sorted. The rest of the input data is assigned to the properties in lst. create allocates heap memory, and builds temporary files which increase disk requirements while it runs. No explicit lock should be established on the database, and no other processes should operate on this database while it runs. When creating more than a few hundred million index entries per file, it might be necessary to increase the number of open files with e.g. ulimit -n 10000. See also dbs, new, commit and prune.
# Minimal E/R model
(class +Cls +Entity)          # Class
(rel key (+Key +Number))      # with a unique numeric key,
(rel num (+Ref +Number))      # an indexed number,
(rel str (+Ref +String))      # and an indexed string

   (0 +Cls)
   (4 (+Cls key))             # Each index in a different file
   (4 (+Cls num))
   (4 (+Cls str)) )

# Generating random data
(create '(+Cls) 'key '(num str)
   (co 'go                 # Use a coroutine as generator
      (for Key 100000000   # Key is sorted in input
         (yield            # Return keys, numbers and single-char strings
            (list Key (rand) (char (rand 97 122))) ) ) ) )

# Reading from a file in PLIO format
(create '(+Cls) 'key '(num str)
   (rd) )

# Reading from a TAB-separated CSV file
(create '(+Cls) 'key '(num str)
   (when (split (line) "\t")
         (format (car @))
         (format (cadr @))
         (pack (caddr @)) ) ) )

# Direct, naive approach (without using 'create')
# Don't try this at home! Takes forever due to disk trashing
(prune 0)
(gc 400 200)
(for Key 100000000
   (new `(db: +Cls) '(+Cls)
      'key Key
      'num (rand)
      'str (char (rand 97 122)) )
   (at (0 . 10000) (commit) (prune 7)) )
(gc 0)
(ctl 'sym . prg) -> any
Waits until a write (exclusive) lock (or a read (shared) lock if the first character of sym is "+") can be set on the file sym, then executes prg and releases the lock. If the file does not exist, it will be created. When sym is NIL, a shared lock is tried on the current innermost I/O channel, and when it is T, an exclusive lock is tried instead. See also in, out, err and pipe.
$ echo 9 >count                           # Write '9' to file "count"
$ pil +
: (ctl ".ctl"                             # Exclusive control, using ".ctl"
   (in "count"
      (let Cnt (read)                     # Read '9'
         (out "count"
            (println (dec Cnt)) ) ) ) )   # Write '8'
-> 8
$ cat count                               # Check "count"
(ctty 'pid) -> pid
(ctty 'any) -> any | NIL
Unless called with a short number, ctty changes the current TTY device to any (or just sets standard I/O to a PTY if any is NIL). Otherwise, the local console is prepared for serving the PicoLisp process with the process ID pid. See also raw.
: (ctty "/dev/tty")
-> "/dev/tty"
(curry lst . fun) -> fun
Builds a new function from the list of symbols or symbol-value pairs lst and the functional expression fun. Each member in lst that is a pat? symbol is substituted inside fun by its value. All other symbols in lst are collected into a job environment. curry is a general higher-order function, not limited to strict currying (which generates only single-argument functions).
: (de multiplier (@X)
   (curry (@X) (N) (* @X N)) )
-> multiplier
: (multiplier 7)
-> ((N) (* 7 N))
: ((multiplier 7) 3)
-> 21

: (def 'fiboCounter
   (curry ((N1 . 0) (N2 . 1)) (Cnt)
      (do Cnt
               (+ N1 N2)
               (setq N1 N2  N2 @) ) ) ) ) )
-> fiboCounter
: (pp 'fiboCounter)
(de fiboCounter (Cnt)
   (job '((N2 . 1) (N1 . 0))
      (do Cnt
            (prog1 (+ N1 N2) (setq N1 N2 N2 @)) ) ) ) )
-> fiboCounter
: (fiboCounter 5)
-> 8
: (fiboCounter 5)
-> 89
(cut 'cnt 'var) -> lst
Pops the first cnt elements (CAR) from the stack in var. See also pop, rid and del.
: (setq S '(1 2 3 4 5 6 7 8))
-> (1 2 3 4 5 6 7 8)
: (cut 3 'S)
-> (1 2 3)
: S
-> (4 5 6 7 8)