shithub: sl

Download patch

ref: 563be734f173290547a09638d7a029c74a9cc195
parent: 3c7f165fa70a9c0e2a2d300fe6deb49db00f1d05
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Fri May 9 23:59:32 EDT 2025

str-trim: use two predicates instead of strings with runes to remove

This is a much more useful version. It also allows to get rid of
*whitespace* value.

--- a/boot/sl.boot
+++ b/boot/sl.boot
@@ -18,7 +18,7 @@
   value))  positive? ((n))  atan ((x) (y x))  remprop ((symbol key))  delete-file ((path))  cdddar ((lst))  set-cdr! ((cell
   new-second))  stacktrace (NIL)  eq? ((a b))  io->str ((io))  bound? ((sym))  list->vec ((l))  odd? ((n))  list? ((v))  str-rep ((term
   k))  time ((expr))  sym ((term . rest))  tanh ((r))  for ((min max f))  const? ((term))  str-trim ((s
-  (at-start *whitespace*) (at-end at-start)))  tan ((r))  table (rest)  __rcscript (NIL)  doc-group ((group-name
+  (lead-pred rune-whitespace?) (trail-pred lead-pred)))  tan ((r))  table (rest)  __rcscript (NIL)  doc-group ((group-name
   doc))  cdaaar ((lst))  bounds-error (args)  even? ((n))  zero? ((n))  proper-list? ((v))  random ((max))  reverse! ((lst))  eval ((x))  cdaadr ((lst))  u32 (((n
   0)))  cons ((first second))  filter ((pred lst))  assq ((key lst))  del! ((table key))  vec? ((v))  min ((v . rest))  cddaar ((lst))  io? ((term))  eof-object? ((v))  help ((topic
   (:print-header help-print-header) . rest))  mod ((a n))  p32 (((n 0)))  io-read-lines ((io))  sym-set-doc ((symbol
@@ -58,7 +58,7 @@
   group list) "Working with lists."  delete-file "Delete the file from the filesystem.\n\nThrows an IO error if file does not exist or it failed to be deleted."  (doc
   group array) "Arrays and vectors."  cdddar "Shorthand for (cdr (cdr (cdr (car lst))))."  set-cdr! "Modify a cons cell (a list) in-place by putting `new-second` as its\nsecond element (tail of the list).  Return the modified cons\ncell (list).\n\nExamples:\n\n    (def q '(1 2 3 4 5))\n    (set-cdr! q '(6 7))\n    ; ↳ (1 6 7)\n    q\n    ; ↳ (1 6 7)"  stacktrace "Return the current stack trace."  eq? "Return `T` if `a` and `b` are the same object, `NIL` otherwise.\n\nExamples:\n\n    (eq? 0.0 0)\n    ; ↳ NIL\n\n    (eq? 0 0)\n    ; ↳ T\n\n    (def a \"1\")\n    (def b \"1\")\n    (eq? a b)\n    ; ↳ NIL\n\n    (def a '(1))\n    (def b '(1))\n    (eq? a b)\n    ; ↳ NIL"  io->str "Return the data of the in-memory `io` buffer as a string."  bound? "Return `T` if `sym` has a value associated with it, `NIL` otherwise.\n\nExamples:\n\n    (bound? 'bound?)\n    ; ↳ T\n\n    (bound? 'doesnotcompute)\n    ; ↳ NIL"  list->vec "Return the list converted to a vector.\n\nExamples:\n\n    (list->vec '(1 2 a))\n    ; ↳ #(1 2 a)"  odd? "Return `T` if `n` is an odd integer, `NIL` otherwise."  list? "Return `T` if the value is either `NIL` or a cons cell, `NIL`\notherwise."  *os-version* "The \"version\" of the operating system this StreetLISP VM executable\nwas built for.\n\nThe availability of the constant and its value depends on the\noperating system and is only provided for the user to see.  No logic\nshould depend on it.\n\nExamples:\n\n    *os-version*\n    ; ↳ \"6.14.5-0-edge\" ; Alpine Linux kernel version"  str-rep "Return the concatenation of the term formatted as a string, repeated\n`k` times.\n\nExamples:\n\n    (str-rep \"oi\" 3)\n    ; ↳ \"oioioi\"\n\n    (str-rep #\\ы 5)\n    ; ↳ \"ыыыыы\"\n\n    (str-rep 'a 3)\n    ; ↳ \"aaa\"\n\n    (str-rep 1 5)\n    ; ↳ \"11111\""  time "Display the elapsed time of evaluating `expr` to `*io-out*`, return\nthe result of the evaluated expression.\n\nExamples:\n\n    (time (begin (sleep 0.1) 12345))\n    ; ‼ Elapsed time: 0.10013356 seconds\n    ; ↳ 12345"  sym "Return a symbol with the name being the concatenation of terms\nformatted as strings.\n\nThis is equivalent to `(sym (str …))`.\n\nExamples:\n\n    (sym \"a\" 'b 1)\n    ; ↳ ab1"  tanh "Return the hyperbolic tangent of `x`."  for "Call the function `f` with a single integer argument, starting from\n`min` and ending with `max`.\n\nExamples:\n\n    (for 0 2 (λ (i) (print (- 2 i))))\n    ; ↳ 210"  (doc
   group vm) "VM-related functions."  const? "Return `T` if the term refers to a constant, `NIL` otherwise.\n\nConstants cannot be modified with `set!`.  Trying to do so will result\nin an exception.\n\nExamples:\n\n    (const? 12345) ; a number\n    ; ↳ T\n\n    (const? 'const?) ; a function\n    ; ↳ NIL\n\n    (const? 'pi) ; a mathematical constant\n    ; ↳ T"  (doc
-  group rand) "Random numbers generation."  str-trim "Return the portion of the string with all leading runes in `at-start`\nand/or trailing runes in `at-end` removed.\n\nWithout runes to remove specified, `str-trim` will remove whitespace\n(defined as `*whitespace*`) from both sides of the string.\n\nExamples:\n\n    (str-trim \" \\nhello\\t\\v\")\n    ; ↳ \"hello\"\n\n    (str-trim \" \\nhello\\t\\v\" \" \\v\")\n    ; ↳ \"\\nhello\\t\"\n\n    (str-trim \"123abcdef456\" \"13\" \"46\")\n    ; ↳ \"23abcdef45\""  *stderr* "Standard error output IO stream."  tan "Return the tangent of `r`, where `r` is given in radians."  table "Construct a table from keys from the arguments.\n\nEvery two arguments are expected to be a key and a value associated\nwith that key.\n\nExamples:\n\n    (table)\n    ; ↳ #table()\n\n    (table 'a 1 'b 2)\n    ; ↳ #table(a 1 b 2)"  __rcscript "Execute, if exists, the user's \"run commands\" file.\n\nThe file path is predefined and depends on the OS:\n\n * `$home/lib/slrc` on Plan 9\n * `$HOME/.slrc` on other operating systems\n\nIt is automatically loaded by StreetLISP when running in interactive\nmode.  The user may wish to use this file to change the look of the\nprompt, load additional functionality they want to use without having\nto do the process manually each time, and so on."  doc-group "Define documentation for a group."  cdaaar "Shorthand for (cdr (car (car (car lst))))."  bounds-error "Raise a bounds error exception."  even? "Return `T` if `n` is an even integer, `NIL` otherwise."  *properties* "All properties of symbols recorded with `putprop` are recorded in this\ntable."  zero? "Return `T` if `n` is zero. Shorthand for `(= n 0)`."  proper-list? "Return `T` is the value is a proper list.  That is, a non-circular\nlist with the last element being `NIL`, as opposed to a dotted list.\n\nExamples:\n\n    ; empty list\n    (proper-list? NIL)\n    ; ↳ T\n\n    ; a list with one element\n    (proper-list? '(1))\n    ; ↳ T\n\n    ; a pair, cdr of the cell is 2\n    (proper-list? '(1 . 2))\n    ; ↳ NIL\n\n    ; on a circular list\n    (def l '(1))\n    (set-cdr! l l)\n    ; ↳ #0=(1 . #0#)\n    (length l)\n    ; ↳ +inf.0\n    (proper-list? l)\n    ; ↳ NIL"  random "Return a random number in the range `[0, max]` (inclusive).\n\nThe result is either an integer or a floating point number, depending\non the type of the `max` argument.\n\nExamples:\n\n    (random 1)\n    ; ↳ 1\n\n    (random 1.0)\n    ; ↳ 0.69517"  reverse! "Return the list with its elements in reverse order.\n\nThe original list may be modified by this function since it's a\ndestructive operation.\n\nExamples:\n\n    (def a '(1 2 3))\n    (reverse! a)\n    ; ↳ (3 2 1)\n    a\n    ; ↳ (1) ; original list has been modified in-place"  *directory-separator* "OS-specific path separator.\n\nIt is preferred over hardcoded `\"/\"`, for portability."  eval "Evaluate expression.\n\nExamples:\n\n    (eval '(begin (set! x 1) (set! y 2) (+ x y)))\n    ; ↳ 3\n    x\n    ; ↳ 1\n    y\n    ; ↳ 2"  cdaadr "Shorthand for (cdr (car (car (cdr lst))))."  u32 "Construct a 32-bit unsigned number."  cons "Return a cons cell containing two arguments.\n\nExamples:\n\n    (cons 1 2)\n    ; ↳ (1 . 2)\n\n    (cons 1 '(2))\n    ; ↳ (1 2)\n\n    (cons 1 (cons 2 (cons 3 NIL)))\n    ; ↳ (1 2 3)"  filter "Return a copy of the list with only the elements of the original\nthat satisfy the predicate.\n\nExamples:\n\n    (filter odd? '(0 1 2 3 4))\n    ; ↳ (1 3)"  assq "Return a pair of a matching key and the associated value, or `NIL` if\nnone matched.  Keys are compared using `eq?`."  most-positive-fixnum "A constant integer closest to positive infinity that can be\nrepresented by fixnum type on this particular platform."  del! "Remove any existing mapping for `key` and return the table.\n\nExamples:\n\n    (def t #table(a 1 b 2))\n    (del! t 'c)\n    ; ↳ #table(b 2  a 1)\n    (del! t 'b)\n    ; ↳ #table(a 1)\n    t\n    ; ↳ #table(a 1)"  vec? "Return `T` if `v` is a vector, `NIL` otherwise."  min "Return the smalles
\ No newline at end of file
+  group rand) "Random numbers generation."  str-trim "Return the portion of the string with all leading runes satisfying\n`lead-pred` (and trailing runes satisfying `trail-pred`) removed.\n\nWithout predicates explicitly specified, `str-trim` will remove\nwhitespace from both sides of the string.\n\nPass `NIL` as the predicate to disable trimming on either side.\n\nExamples:\n\n    (str-trim \" \\nhello\\t\\v\")\n    ; ↳ \"hello\"\n\n    (str-trim \" \\nhello\\t\\v\"\n              (λ (r) (str-find \" \\v\" r)))\n    ; ↳ \"\\nhello\\t\"\n\n    (str-trim \"123abc!456def\"\n              rune-numeric?\n              rune-alphabetic?)\n    ; ↳ \"abc!456\""  *stderr* "Standard error output IO stream."  tan "Return the tangent of `r`, where `r` is given in radians."  table "Construct a table from keys from the arguments.\n\nEvery two arguments are expected to be a key and a value associated\nwith that key.\n\nExamples:\n\n    (table)\n    ; ↳ #table()\n\n    (table 'a 1 'b 2)\n    ; ↳ #table(a 1 b 2)"  __rcscript "Execute, if exists, the user's \"run commands\" file.\n\nThe file path is predefined and depends on the OS:\n\n * `$home/lib/slrc` on Plan 9\n * `$HOME/.slrc` on other operating systems\n\nIt is automatically loaded by StreetLISP when running in interactive\nmode.  The user may wish to use this file to change the look of the\nprompt, load additional functionality they want to use without having\nto do the process manually each time, and so on."  doc-group "Define documentation for a group."  cdaaar "Shorthand for (cdr (car (car (car lst))))."  bounds-error "Raise a bounds error exception."  even? "Return `T` if `n` is an even integer, `NIL` otherwise."  *properties* "All properties of symbols recorded with `putprop` are recorded in this\ntable."  zero? "Return `T` if `n` is zero. Shorthand for `(= n 0)`."  proper-list? "Return `T` is the value is a proper list.  That is, a non-circular\nlist with the last element being `NIL`, as opposed to a dotted list.\n\nExamples:\n\n    ; empty list\n    (proper-list? NIL)\n    ; ↳ T\n\n    ; a list with one element\n    (proper-list? '(1))\n    ; ↳ T\n\n    ; a pair, cdr of the cell is 2\n    (proper-list? '(1 . 2))\n    ; ↳ NIL\n\n    ; on a circular list\n    (def l '(1))\n    (set-cdr! l l)\n    ; ↳ #0=(1 . #0#)\n    (length l)\n    ; ↳ +inf.0\n    (proper-list? l)\n    ; ↳ NIL"  random "Return a random number in the range `[0, max]` (inclusive).\n\nThe result is either an integer or a floating point number, depending\non the type of the `max` argument.\n\nExamples:\n\n    (random 1)\n    ; ↳ 1\n\n    (random 1.0)\n    ; ↳ 0.69517"  reverse! "Return the list with its elements in reverse order.\n\nThe original list may be modified by this function since it's a\ndestructive operation.\n\nExamples:\n\n    (def a '(1 2 3))\n    (reverse! a)\n    ; ↳ (3 2 1)\n    a\n    ; ↳ (1) ; original list has been modified in-place"  *directory-separator* "OS-specific path separator.\n\nIt is preferred over hardcoded `\"/\"`, for portability."  eval "Evaluate expression.\n\nExamples:\n\n    (eval '(begin (set! x 1) (set! y 2) (+ x y)))\n    ; ↳ 3\n    x\n    ; ↳ 1\n    y\n    ; ↳ 2"  cdaadr "Shorthand for (cdr (car (car (cdr lst))))."  u32 "Construct a 32-bit unsigned number."  cons "Return a cons cell containing two arguments.\n\nExamples:\n\n    (cons 1 2)\n    ; ↳ (1 . 2)\n\n    (cons 1 '(2))\n    ; ↳ (1 2)\n\n    (cons 1 (cons 2 (cons 3 NIL)))\n    ; ↳ (1 2 3)"  filter "Return a copy of the list with only the elements of the original\nthat satisfy the predicate.\n\nExamples:\n\n    (filter odd? '(0 1 2 3 4))\n    ; ↳ (1 3)"  assq "Return a pair of a matching key and the associated value, or `NIL` if\nnone matched.  Keys are compared using `eq?`."  most-positive-fixnum "A constant integer closest to positive infinity that can be\nrepresented by fixnum type on this particular platform."  del! "Remove any existing mapping for `key` and return the table.\n\nExamples:\n\n    (def t #table(a 1 b 2))\n    (del! t 'c)\n    ; ↳ #table(b 2  a 1)\n   
\ No newline at end of file
 t among the arguments.\n\nExamples:\n\n    (min 3 1 9 4)\n    ; ↳ 1\n\n    (min 'c 'h 'z 'a)\n    ; ↳ a\n\n    (min \"t\" \"g\" \"a\")\n    ; ↳ \"a\""  cddaar "Shorthand for (cdr (cdr (car (car lst))))."  io? "Return `T` if `term` is of `io` type, `NIL` otherwise."  eof-object? "Return `T` if the argument is `#<eof>`, `NIL` otherwise.\n\nThis object is returned by I/O functions to signal end of file,\nwhere applicable."  help "Display documentation for a specific term or group of terms, if\navailable.\n\nAn optional symbol `group` is used to query for documentation on a\ngroup instead of a single term.  All available documentation groups\ncan be displayed with `(help groups)`.\n\nAsterisk can be added to the beginning and/or end of the term in order\nto list the matching terms defined in the current environment.  This\ncan be useful to recall a function's name.\n\nExamples:\n\n    (help str?)       ; show documentation for str?\n    (help groups)     ; show documentation groups\n    (help type group) ; list items for dealing with types\n    (help group type) ; same as ^\n    (help str->*)     ; find functions converting from strings\n    (help *->str)     ; find functions converting to strings\n    (help *num*)      ; find anything related to numbers"  mod "Return the remainder of the Euclidean division `a/n`.\n\nExamples:\n\n    (mod  10 3)\n    ; ↳ 1\n\n    (mod -10 3)\n    ; ↳ 2\n\n    (mod -10 -3)\n    ; ↳ 2\n\n    (mod  10 -3)\n    ; ↳ 1"  p32 "Construct a 32-bit abstract pointer value."  io-read-lines "Return a list of lines read from the IO object until it ran out of\ndata.\n\nThe file is split into lines by `#\\linefeed`.  Each string will have\nthe character, except the last line if EOF has been reached\nbeforehand.\n\nExamples:\n\n    ; read current process' segments on Plan 9\n    (def seg (file (str \"/proc/\" (getpid) \"/segment\")))\n    (io-read-lines seg)\n    ; ↳ (\"Stack     1feff0000 1ffff0000    1\\n\"\n         \"Text   R     10000    70000    1\\n\"\n         \"Data         70000    d0000    1\\n\"\n         \"Bss          d0000   1a0000    1\\n\"\n         \"Bss       1fcff0000 1feff0000    1\\n\"\n         \"Bss       1faff0000 1fcff0000    1\\n\")"  sym-set-doc "Set the documentation for the symbol."  macrocall? "Return the macro application function if `e` refers to a macro call,\n`NIL` otherwise.\n\nExamples:\n\n    (macrocall? '(car NIL))\n    ; ↳ NIL\n\n    (macrocall? '(let ((x 1)) 2))\n    ; ↳ #fn(...)"  *syntax-environment* "Table containing macro definitions.\n\nThe keys are macro names, the values are their application functions."  table-values "Return the list of all values of the table.\n\nExamples:\n\n    (def t #table(a 1 b 2 c 1))\n    (table-values t)\n    ; ↳ (1 2 1)"  macroexpand "Return a fully macro-expanded expression.\n\nExpansion will continue until no more macro calls are left.\n\nExamples:\n\n    (let ((a 3) (b 4) (c 5))\n      (macroexpand `(let* {[x ,a] [y ,b]} (+ x y ,c))))\n    ; ↳ ((λ (x)\n           ((λ (y)\n              (+ x y 5))\n            4))\n         3)"  caadr "Shorthand for (car (car (cdr lst)))."  defstruct "Declare a new structure type with the specified name and slots.\n\nThe default underlying type is a \"named\" vector (`:type vec`), where\nthe first element is the name of the structure's type, the rest are\nthe keyworded slot values.  A list with slot values alone can be used\ninstead by adding `:type list` option.  The list will not contain the\nname of the struct by default, which can be enabled with `:named T`\noption.\n\nAs an example, the following declaration generates the default\nconstructor for a structure of three slots, with one of them (`c`)\nhaving a non-`NIL` default value and marked as read-only:\n\n    (defstruct blah \"Return stuff.\" :doc-group stuff a b (c 1 :read-only T))\n    ; (make-blah (:a NIL) (:b NIL) (:c 1))\n    ; (blah-a s)\n    ; (blah-b s)\n    ; (blah-c s)\n\nSlot's options, if any, should be specified after its default value.\nSupported options are:\n\n    ; mark the slot as read-only\n    ;
\ No newline at end of file
   group misc) "Miscellaneous."  < "Return `T` if the arguments are in strictly increasing order (next\none is greater than the previous one).  With a single argument\nthe result is always `T`."  f32 "Construct a 32-bit floating point number."  sin "Return the sine of `r`, where `r` is given in radians."  delete-duplicates "Return a copy of the list with duplicated elements removed.\n\nElements are tested for duplicates using `equal?`.  The order of the\nelements is preserved in the resulting list.\n\nExamples:\n\n    (delete-duplicates '(a 0 b c1 a b 3 c 5))\n    ; ↳ (a 0 b c1 3 c 5)"  > "Return `T` if the arguments are in strictly decreasing order (previous\none is greater than the next one)."  str-rune "Return the nth rune of the string.\n\nThrows an exception if the index `n` is out of bounds.\n\nExamples:\n\n    (str-rune \"йцукен\" 3)\n    ; ↳ #\\к"  (doc
   group number) "Operations on numbers, mathematical constants."  with-output-to "Evaluate expressions in `body` with `*io-out*` set to `io` during the\nevaluation.\n\nExamples:\n\n    ; write a string \"hello, world!\" to a file\n    ; end with a newline\n    (with-output-to (file \"/tmp/1.txt\" :create :truncate :write)\n      (print \"hello, world!\")\n      (newline))"  abs "Return absolute value of the argument."  *linefeed* "OS-specific _line_ _feed_ value.\n\nIt is preferred over hardcoded `\"\\n\"`, for portability."  str? "Return `T` if the argument is a string, `NIL` otherwise."  cons? "Return `T` if `v` is a cons cell, `NIL` otherwise.\n\nExamples:\n\n    (cons? 0)\n    ; ↳ NIL\n\n    (cons? NIL)\n    ; ↳ NIL\n\n    (cons? '(1))\n    ; ↳ T"  aset! "Modify the sequence element specified by the subscripts and return the\nnew value.  The sequence can be an array, vector, a list.\nMulti-dimensional sequences of variating types are also supported.\n\nExamples:\n\n    (def a '((1 #(2 (3)) 4)))\n    (aset! a 1 'x)\n    ; ‼ index 1 out of bounds\n    (aset! a 0 0 'x)\n    ; ↳ x\n    a\n    ; ↳ ((x #(2 (3)) 4))\n    (aset! a 0 1 9)\n    ; ↳ 9\n    a\n    ; ↳ ((x #(9 (3)) 4))"  T "A boolean \"true\".\n\nExamples:\n\n    (not T)\n    ; ↳ NIL\n\n    (if T 'yes 'no)\n    ; ↳ yes"  - "Return the result of subtraction.  With only one argument a\nnegation is performed.\n\nExamples:\n\n    (- 1.5)\n    ; ↳ -1.5\n\n    (- 3 2)\n    ; ↳ 1"  rand "Return a random non-negative fixnum on its maximum range."  (doc
@@ -74,7 +74,7 @@
  call\nthe name and arguments will be printed to `*io-out*`.\n\nExamples:\n\n    (trace 'map)\n    (map odd? (list (+ 1 2) (+ 3 4)))\n    ; ‼ (map #fn(\"n170051S:\" #(even?) odd? 6) (3 7))\n    ; ↳ (T T)"  gensym? "Return `T` if the argument is a gensym, `NIL` otherwise."  cdddr "Shorthand for (cdr (cdr (cdr lst)))."  copy-table "Return a new copy of the table with the keys and values preserved.\n\nExamples:\n\n    (def t #table(a (1 2 3)))\n    (def q (copy-table t))\n    (eq? t q)\n    ; ↳ NIL\n    (eq? (get t 'a) (get q 'a))\n    ; ↳ T"  set-car! "Modify a cons cell (a list) in-place by putting `new-first` as its\nfirst element (head of the list).  Return the modified cons\ncell (list).\n\nExamples:\n\n    (def q '(1 2 3 4 5))\n    (set-car! q 0)\n    ; ↳ (0 6 7)\n    q\n    ; ↳ (0 6 7)"  partition "Return two lists where the first contains the elements of the original\nlist which satisfy the predicate and the second containing the rest of\nthe elements.\n\nBoth lists will have the elements appear in the same order as in the\noriginal list.\n\nExamples:\n\n    ; split the list into numbers and non-numbers\n    (def q '(1a 1 0 2b e 3))\n    (receive (nums other) (partition num? q)\n      (print nums other)\n      (newline))\n    ; ↳ (1 0 3) (1a 2b e)"  has? "Return `T` if the table has a value associated with the key, `NIL` otherwise.\n\nExamples:\n\n    (def t #table(a 1 b 2))\n    (has? t 'c)\n    ; ↳ NIL\n    (has? t 'a)\n    ; ↳ T"  vec "Construct a vector containing the specified arguments.\n\nExamples:\n\n    (vec) ; empty vector\n    ; ↳ #()\n\n    (vec 1 2.5 \"a\" 'b)\n    ; ↳ #(1 2.5 \"a\" b)"  rune "Construct a rune from a Unicode code point.  Without code point\nspecified, an \"invalid\" rune is returned."  *exit-hooks* "Internal variable, a list containing functions to call right before VM\nprocess exits."  cadar "Shorthand for (car (cdr (car lst)))."  type-error "Raise a type error exception."  file "Open a file for I/O.\n\nAn `io` object is returned.  Without any modes specified the file\nmust already exist and is opened in read-only mode.\n\nFiles are created with the default mode bits #o644."  nth "Return nth element of the list, or `NIL` if the list is shorter.\n\nExamples:\n\n    (def l '(a b c))\n    (nth l 0)\n    ; ↳ a\n    (nth l 2)\n    ; ↳ c\n    (nth l 10)\n    ; ↳ NIL"  cdr "Return the second element of a cons cell (tail of a list) or `NIL` if\nnot available.\n\nExamples:\n\n    (cdr NIL)\n    ; ↳ NIL\n\n    (cdr '(1 2 3))\n    ; ↳ (2 3)\n\n    (cdr '(1 . 2))\n    ; ↳ 2"  / "Return the division of the arguments.  With only one argument the\nresult of `1/x` is returned.  If the result is integer-valued, it is\nreturned as an integer.\n\nExamples:\n\n    (/ 2)\n    ; ↳ 0.5\n\n    (/ 7 2 2)\n    ; ↳ 1.75\n\n    (/ 10 -2)\n    ; ↳ -5 ; a fixnum\n\n    (/ 6.9 1.9)\n    ; ↳ 3.6315…"  newline "Write a single OS-specific line feed to the output.\n\nOn most systems it's a single character - `#\\linefeed` (`\\n`)."  separate-doc-from-body "Take a list of terms and return a pair `(doc . body)`, where the first\nelement contains a list of documentation-related terms, and the second\ncontains the rest of the terms."  rand-u64 "Return a random integer on interval [0, 2⁶⁴-1]."  cdadar "Shorthand for (cdr (car (cdr (car lst))))."  sqrt "Return the square root of `x`.\n\nExamples:\n\n    (sqrt 9.0)\n    ; ↳ 3.0"  reverse "Return the list with its elements in reverse order.\n\nThe original list is copied to construct the reversed version.\n\nExamples:\n\n    (def a '(1 2 3))\n    (reverse a)\n    ; ↳ (3 2 1)\n    a\n    ; ↳ (1 2 3)"  lz-pack "Return data compressed using Lempel-Ziv.\n\nThe data must be an array, returned value will have the same type.\nThe optional `level` is between `0` and `10`.  With `level` set to\n`0` a simple LZSS using hashing will be performed.  Levels between\n`1` and `9` offer a trade-off between time/space and ratio.  Level\n`10` is optimal but very slow."  *prompt* "Function called by REPL to tell the user it's expecting input.\
\ No newline at end of file
   group io) "Files and I/O functionality."  traced? "Return `T` if the tracing is enabled for the function, `NIL`\notherwise.\n\nExamples:\n\n    (traced? map)\n    ; ↳ NIL\n    (trace 'map)\n    (traced? map)\n    ; ↳ T\n    (untrace 'map)\n    (traced? map)\n    ; ↳ NIL"  (doc
   group builtin) "Built-in operators."  s64 "Construct a 64-bit signed number."  NIL "An empty list.  Can be used as the opposite of T in boolean\nexpressions.\n\nExamples:\n\n    (not NIL)\n    ; ↳ T\n\n    (if NIL 'yes 'no)\n    ; ↳ no\n\n    (car NIL)\n    ; ↳ NIL\n\n    (cdr NIL)\n    ; ↳ NIL"  assoc "Return a pair of a matching key and the associated value, or `NIL` if\nnone matched.  Keys are compared using `equal?`.\n\nExamples:\n\n    (def L (assoc-list 'a 0 'b 1))\n    (assoc 'b L)\n    ; ↳ (b . 1)\n    (assoc 'c L)\n    ; ↳ NIL"  + "Return sum of the arguments or `0` when none specified."  cadadr "Shorthand for (car (cdr (car (cdr lst))))."  (doc
-and `10`.  With `level` set to\n`0` a simple LZSS using hashing will be performed.  Levels between\n`1` and `9` offer a trade-off between time/space and ratio.  Level\n`10` is optimal but very slow."  *prompt* "Function called by REPL to tell the user it's expecting input.\n\nThe default `*prompt*` function prints `#;> `, which by itself is a\ncommented-out expression, allowing the user to copy-paste the entire\nline (with the prompt) to re-evaluate."  member "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `equal?`.\n\nExamples:\n\n    (member 1 '(3 2 1 0))\n    ; ↳ (1 0)\n\n    (member 1 '(2 3))\n    ; ↳ NIL"  bignum? "Return `T` if the argument is a bignum, `NIL` otherwise."  memq "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `eq?`."  f64 "Construct a 64-bit floating point number."  fixnum "Construct a fixnum."  str->num "Return the number using the radix `base` in the string `s`.\n\nReturns `NIL` if the number could not be parsed or there were\nleft-over trailing characters.\n\nExamples:\n\n    (str->num \"1.2\")\n    ; ↳ 1.2\n\n    (str->num \"#x123\")\n    ; ↳ 291\n\n    (str->num \"ffff\" 16)\n    ; ↳ 65535\n\n    (str->num \"777\" 8)\n    ; ↳ 511"  exp "Return the exponential - value of `e` (natural logarithms base) raised\nto the power of `p`.\n\nExamples:\n\n    (exp 1)\n    ; ↳ 2.71828… ; e¹"  caaaar "Shorthand for (car (car (car (car lst))))."  (doc
+eturn data compressed using Lempel-Ziv.\n\nThe data must be an array, returned value will have the same type.\nThe optional `level` is between `0` and `10`.  With `level` set to\n`0` a simple LZSS using hashing will be performed.  Levels between\n`1` and `9` offer a trade-off between time/space and ratio.  Level\n`10` is optimal but very slow."  *prompt* "Function called by REPL to tell the user it's expecting input.\n\nThe default `*prompt*` function prints `#;> `, which by itself is a\ncommented-out expression, allowing the user to copy-paste the entire\nline (with the prompt) to re-evaluate."  member "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `equal?`.\n\nExamples:\n\n    (member 1 '(3 2 1 0))\n    ; ↳ (1 0)\n\n    (member 1 '(2 3))\n    ; ↳ NIL"  bignum? "Return `T` if the argument is a bignum, `NIL` otherwise."  memq "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `eq?`."  f64 "Construct a 64-bit floating point number."  fixnum "Construct a fixnum."  str->num "Return the number using the radix `base` in the string `s`.\n\nReturns `NIL` if the number could not be parsed or there were\nleft-over trailing characters.\n\nExamples:\n\n    (str->num \"1.2\")\n    ; ↳ 1.2\n\n    (str->num \"#x123\")\n    ; ↳ 291\n\n    (str->num \"ffff\" 16)\n    ; ↳ 65535\n\n    (str->num \"777\" 8)\n    ; ↳ 511"  exp "Return the exponential - value of `e` (natural logarithms base) raised\nto the power of `p`.\n\nExamples:\n\n    (exp 1)\n    ; ↳ 2.71828… ; e¹"  caaaar "Shorthand for (car (car (car (car lst))))."  (doc
 if `v` is a symbol, `NIL` otherwise."  u64 "Construct a 64-bit unsigned number."  Instructions "VM instructions mapped to their encoded byte representation."  assv "Return a pair of a matching key and the associated value, or `NIL` if\nnone matched.  Keys are compared using `eqv?`."  bignum "Construct a bignum.  As opposed to a fixnum, its value is not limited."  (doc
   group syntax) "StreetLISP syntax and macros."  *os-name* "The name of the operating system this StreetLISP VM executable was\nbuilt for.\n\nIt's set to a lowercase string and its value is considered \"best\neffort\" - it might not always be accurate.\n\nPossible values: `\"unknown\"`, `\"plan9\"`, `\"linux\"`, `\"openbsd\"`,\n`\"netbsd\"`, `\"dragonflybsd\"`, `\"freebsd\"`, `\"haiku\"`, `\"macosx\"`,\n`\"macos\"`, `\"dos\"`."  eqv? "Return `T` if both `a` and `b` are of the same value and primitive\n(leaf) type, `NIL` otherwise.  Neither cons cell nor vector are not\nconsidered primitive types as they may define deep structures.\n\nExamples:\n\n    (eqv? 0.0 0)\n    ; ↳ NIL\n\n    (eqv? 0 0)\n    ; ↳ T\n\n    (def a \"1\")\n    (def b \"1\")\n    (eqv? a b)\n    ; ↳ T\n\n    (def a '(1))\n    (def b '(1))\n    (eqv? a b)\n    ; ↳ NIL"  list "Return a list constructed of the arguments.\n\nExamples:\n\n    (list) ; empty list\n    ; ↳ NIL\n\n    (list 1 2.5 \"a\" 'b)\n    ; ↳ (1 2.5 \"a\" b)"  __init_globals "Initialize globals that need to be set at load time."  (doc
   group doc) "Writing and reading documentation."  rand-u32 "Return a random integer on interval [0, 2³²-1]."  revappend "Return list with its elements in reverse order, with `tail` appended\nto its end.\n\nThe original list is copied to construct the reversed version.\n\nExamples:\n\n    (def a '(4 5 6))\n    (revappend a '(3 2 1))\n    ; ↳ (6 5 4 3 2 1)\n    a\n    ; ↳ (4 5 6)"  (doc
@@ -95,7 +95,7 @@
 \n    ; ↳ (6 5 4 3 2 1)"  defc*r "Define a shorthand for list access using `car` and `cdr`.\n\nExamples:\n\n    (defc*r caaaaaaaaddr) ; define the function"  read-all-of "Call `fn` on an IO object until it runs out of data.  Return the list\ncontaining the values returned by `fn` on each call."  cddddr "Shorthand for (cdr (cdr (cdr (cdr lst))))."  logior "Return the result of bitwise OR (inclusive OR) operation on integers.\n\nExamples:\n\n    (logior)\n    ; ↳ 0\n\n    (logior 2)\n    ; ↳ 2\n\n    (logior 2 3)\n    ; ↳ 3\n\n    (logior 2 3 4)\n    ; ↳ 7"  cadr "Shorthand for `(car (cdr lst))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n    (cadr '(1 2 3))\n    ; ↳ 2\n\n    (cadr '(1))\n    ; ↳ NIL\n\n    (cadr NIL)\n    ; ↳ NIL"  cdadr "Shorthand for (cdr (car (cdr lst)))."  nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise."  caar "Shorthand for (car (car lst))."  div0 "Return the quotient of the truncated division `a/n`.\n\nExamples:\n\n    (div0 10 3)\n    ; ↳ 3\n\n    (div0 -10 3)\n    ; ↳ -3\n\n    (div0 -10 -3)\n    ; ↳ 3\n\n    (div0 10 -3)\n    ; ↳ -3"  set-syntax! "Associate a macro name with its application function."  mod0 "Return the remainder of the truncated division `a/n`.\n\nExamples:\n\n    (mod0 10 3)\n    ; ↳ 1\n\n    (mod0 -10 3)\n    ; ↳ -1\n\n    (mod0 -10 -3)\n    ; ↳ -1\n\n    (mod0 10 -3)\n    ; ↳  1"  last-pair "Return the last cell (pair) of the list.\n\nExamples:\n\n    (last-pair '(1 2 3))\n    ; ↳ (3)\n\n    (last-pair '(1 2 . 3))\n    ; ↳ (2 . 3)"  path-cwd "Return the full path to the current directory of the process, or\nchange it to the path specified with `to` argument."  (doc
   group debug) "Debugging utilities."  arr? "Return `T` if the argument is either a vector or an array, `NIL`\notherwise."  cadaar "Shorthand for (car (cdr (car (car lst))))."  unwind-protect "Evaluate `expr` first, then `finally`, regardless of whether\nevaluating the former resulted in any exception thrown or not.\n\nIf an exception has been thrown, it will be raised _after_ evaluating\n`finally`, else the result of `expr` is returned.\n\nExamples:\n\n    (unwind-protect (begin (print \"a\")     (newline)\n                           (print (/ 1 0)) (newline) ; an error here\n                           (print \"b\")     (newline)\n                    (begin (print \"c\")     (newline))))\n    ; ↳ \"a\"\n    ; ↳ \"c\"\n    ; ‼ /: division by zero"  cos "Return the cosine of `r`, where `r` is given in radians."  *io-in* "Current (default) input IO stream.\n\nFunctions may use `*io-in*` for input, which then can be redirected\nfrom a different IO using either `with-input-from` or (a more general)\n`with-bindings`."  every "Return `T` if the predicate is true for _every_ element of the list,\n`NIL` otherwise.\n\nExample:\n\n   ; is every number odd?\n   (every odd? '(1 3 5 7))\n   ; ↳ T\n\n   ; is every string longer than one rune?\n   (every (λ (s) (length> s 1))\n          '(\"ab\" \"cd\" \"e\"))\n   ; ↳ NIL"  atom? "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise.  This is\nthe opposite of `cons?`.\n\nThe term \"atom\" comes from the idea of being indivisible.\n\nExamples:\n\n    (atom? \"a\")\n    ; ↳ T\n\n    (atom? NIL)\n    ; ↳ T\n\n    (atom? '(1))\n    ; ↳ NIL"  p64 "Construct a 64-bit abstract pointer value."  str-utf8? "Return `T` if `s` is a valid UTF-8 string, `NIL` otherwise.\n\nExamples:\n\n    (str-utf8? \"привет\")\n    ; ↳ T\n\n    (str-utf8? \"при\\xffвет\")\n    ; ↳ NIL"  apply "Return the result of applying a function `f` to a list of arguments.\n\nThe last argument must always be a list which gets spliced as\narguments to the function.\n\nExamples:\n\n    (apply + 1 2 '(3 4 5))\n    ; ↳ 15\n\n    (apply vec '(1 2 3))\n    ; ↳ #(3 4 5)\n\n    (apply arr 'u8 '(3 4 5))\n    ; ↳ #vu8(3 4 5)"  cddr "Shorthand for (cdr (cdr lst))."  not "Return `T` if `v` is `NIL`, `T` otherwise."  (doc
   group sys) "OS-specific functions."  print "Print the arguments to *io-out* with `*print-readably*` set to `T`.\n\nMultiple arguments are separated with a single `#\\space`.\n\nExamples:\n\n    (print 1 2 \"abc\")\n    ; ‼ 1 2 \"abc\""  cdar "Shorthand for (cdr (car lst))."  cdaar "Shorthand for (cdr (car (car lst)))."  iota "Return a list of generated indices.\n\nThe sequence of numbers generated will contain the elements\n\n    (start start+step … start+(count-1)*step)\n\nExamples:\n\n    (iota 4)\n    ; ↳ (0 1 2 3)\n\n    (iota 4 6)\n    ; ↳ (6 7 8 9)\n\n    (iota 4 6 -0.5)\n    ; ↳ (6 5.5 5.0 4.5)"  caaddr "Shorthand for (car (car (cdr (cdr lst))))."  environment "Return the list of all bound top level symbols."  getprop "Return a property value associated with the symbol or `def` if\nmissing.\n\nIf the default value is not supplied and the property is missing,\nan exception will be thrown."  (doc
- OR) operation on integers.\n\nExamples:\n\n    (logior)\n    ; ↳ 0\n\n    (logior 2)\n    ; ↳ 2\n\n    (logior 2 3)\n    ; ↳ 3\n\n    (logior 2 3 4)\n    ; ↳ 7"  cadr "Shorthand for `(car (cdr lst))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n    (cadr '(1 2 3))\n    ; ↳ 2\n\n    (cadr '(1))\n    ; ↳ NIL\n\n    (cadr NIL)\n    ; ↳ NIL"  cdadr "Shorthand for (cdr (car (cdr lst)))."  nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise."  caar "Shorthand for (car (car lst))."  div0 "Return the quotient of the truncated division `a/n`.\n\nExamples:\n\n    (div0 10 3)\n    ; ↳ 3\n\n    (div0 -10 3)\n    ; ↳ -3\n\n    (div0 -10 -3)\n    ; ↳ 3\n\n    (div0 10 -3)\n    ; ↳ -3"  set-syntax! "Associate a macro name with its application function."  mod0 "Return the remainder of the truncated division `a/n`.\n\nExamples:\n\n    (mod0 10 3)\n    ; ↳ 1\n\n    (mod0 -10 3)\n    ; ↳ -1\n\n    (mod0 -10 -3)\n    ; ↳ -1\n\n    (mod0 10 -3)\n    ; ↳  1"  last-pair "Return the last cell (pair) of the list.\n\nExamples:\n\n    (last-pair '(1 2 3))\n    ; ↳ (3)\n\n    (last-pair '(1 2 . 3))\n    ; ↳ (2 . 3)"  path-cwd "Return the full path to the current directory of the process, or\nchange it to the path specified with `to` argument."  (doc
+the values returned by `fn` on each call."  cddddr "Shorthand for (cdr (cdr (cdr (cdr lst))))."  logior "Return the result of bitwise OR (inclusive OR) operation on integers.\n\nExamples:\n\n    (logior)\n    ; ↳ 0\n\n    (logior 2)\n    ; ↳ 2\n\n    (logior 2 3)\n    ; ↳ 3\n\n    (logior 2 3 4)\n    ; ↳ 7"  cadr "Shorthand for `(car (cdr lst))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n    (cadr '(1 2 3))\n    ; ↳ 2\n\n    (cadr '(1))\n    ; ↳ NIL\n\n    (cadr NIL)\n    ; ↳ NIL"  cdadr "Shorthand for (cdr (car (cdr lst)))."  nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise."  caar "Shorthand for (car (car lst))."  div0 "Return the quotient of the truncated division `a/n`.\n\nExamples:\n\n    (div0 10 3)\n    ; ↳ 3\n\n    (div0 -10 3)\n    ; ↳ -3\n\n    (div0 -10 -3)\n    ; ↳ 3\n\n    (div0 10 -3)\n    ; ↳ -3"  set-syntax! "Associate a macro name with its application function."  mod0 "Return the remainder of the truncated division `a/n`.\n\nExamples:\n\n    (mod0 10 3)\n    ; ↳ 1\n\n    (mod0 -10 3)\n    ; ↳ -1\n\n    (mod0 -10 -3)\n    ; ↳ -1\n\n    (mod0 10 -3)\n    ; ↳  1"  last-pair "Return the last cell (pair) of the list.\n\nExamples:\n\n    (last-pair '(1 2 3))\n    ; ↳ (3)\n\n    (last-pair '(1 2 . 3))\n    ; ↳ (2 . 3)"  path-cwd "Return the full path to the current directory of the process, or\nchange it to the path specified with `to` argument."  (doc
  ; ↳ 7"  cadr "Shorthand for `(car (cdr lst))`, that is, _first element of the\nsecond element_.\n\nExamples:\n\n    (cadr '(1 2 3))\n    ; ↳ 2\n\n    (cadr '(1))\n    ; ↳ NIL\n\n    (cadr NIL)\n    ; ↳ NIL"  cdadr "Shorthand for (cdr (car (cdr lst)))."  nan? "Return `T` if `v` is a floating point representation of NaN, either\nnegative or positive, `NIL` otherwise."  caar "Shorthand for (car (car lst))."  div0 "Return the quotient of the truncated division `a/n`.\n\nExamples:\n\n    (div0 10 3)\n    ; ↳ 3\n\n    (div0 -10 3)\n    ; ↳ -3\n\n    (div0 -10 -3)\n    ; ↳ 3\n\n    (div0 10 -3)\n    ; ↳ -3"  set-syntax! "Associate a macro name with its application function."  mod0 "Return the remainder of the truncated division `a/n`.\n\nExamples:\n\n    (mod0 10 3)\n    ; ↳ 1\n\n    (mod0 -10 3)\n    ; ↳ -1\n\n    (mod0 -10 -3)\n    ; ↳ -1\n\n    (mod0 10 -3)\n    ; ↳  1"  last-pair "Return the last cell (pair) of the list.\n\nExamples:\n\n    (last-pair '(1 2 3))\n    ; ↳ (3)\n\n    (last-pair '(1 2 . 3))\n    ; ↳ (2 . 3)"  path-cwd "Return the full path to the current directory of the process, or\nchange it to the path specified with `to` argument."  (doc
   group debug) "Debugging utilities."  arr? "Return `T` if the argument is either a vector or an array, `NIL`\notherwise."  cadaar "Shorthand for (car (cdr (car (car lst))))."  unwind-protect "Evaluate `expr` first, then `finally`, regardless of whether\nevaluating the former resulted in any exception thrown or not.\n\nIf an exception has been thrown, it will be raised _after_ evaluating\n`finally`, else the result of `expr` is returned.\n\nExamples:\n\n    (unwind-protect (begin (print \"a\")     (newline)\n                           (print (/ 1 0)) (newline) ; an error here\n                           (print \"b\")     (newline)\n                    (begin (print \"c\")     (newline))))\n    ; ↳ \"a\"\n    ; ↳ \"c\"\n    ; ‼ /: division by zero"  cos "Return the cosine of `r`, where `r` is given in radians."  *io-in* "Current (default) input IO stream.\n\nFunctions may use `*io-in*` for input, which then can be redirected\nfrom a different IO using either `with-input-from` or (a more general)\n`with-bindings`."  every "Return `T` if the predicate is true for _every_ element of the list,\n`NIL` otherwise.\n\nExample:\n\n   ; is every number odd?\n   (every odd? '(1 3 5 7))\n   ; ↳ T\n\n   ; is every string longer than one rune?\n   (every (λ (s) (length> s 1))\n          '(\"ab\" \"cd\" \"e\"))\n   ; ↳ NIL"  atom? "Return `T` if `v` is a _not_ a cons cell, `NIL` otherwise.  This is\nthe opposite of `cons?`.\n\nThe term \"atom\" comes from the idea of being indivisible.\n\nExamples:\n\n    (atom? \"a\")\n    ; ↳ T\n\n    (atom? NIL)\n    ; ↳ T\n\n    (atom? '(1))\n    ; ↳ NIL"  p64 "Construct a 64-bit abstract pointer value."  str-utf8? "Return `T` if `s` is a valid UTF-8 string, `NIL` otherwise.\n\nExamples:\n\n    (str-utf8? \"привет\")\n    ; ↳ T\n\n    (str-utf8? \"при\\xffвет\")\n    ; ↳ NIL"  apply "Return the result of applying a function `f` to a list of arguments.\n\nThe last argument must always be a list which gets spliced as\narguments to the function.\n\nExamples:\n\n    (apply + 1 2 '(3 4 5))\n    ; ↳ 15\n\n    (apply vec '(1 2 3))\n    ; ↳ #(3 4 5)\n\n    (apply arr 'u8 '(3 4 5))\n    ; ↳ #vu8(3 4 5)"  cddr "Shorthand for (cdr (cdr lst))."  not "Return `T` if `v` is `NIL`, `T` otherwise."  (doc
   group sys) "OS-specific functions."  print "Print the arguments to *io-out* with `*print-readably*` set to `T`.\n\nMultiple arguments are separated with a single `#\\space`.\n\nExamples:\n\n    (print 1 2 \"abc\")\n    ; ‼ 1 2 \"abc\""  cdar "Shorthand for (cdr (car lst))."  cdaar "Shorthand for (cdr (car (car lst)))."  iota "Return a list of generated indices.\n\nThe sequence of numbers generated will contain the elements\n\n    (start start+step … start+(count-1)*step)\n\nExamples:\n\n    (iota 4)\n    ; ↳ (0 1 2 3)\n\n    (iota 4 6)\n    ; ↳ (6 7 8 9)\n\n    (iota 4 6 -0.5)\n    ; ↳ (6 5.5 5.0 4.5)"  caaddr "Shorthand for (car (car (cdr (cdr lst))))."  environment "Return the list of all bound top level symbols."  getprop "Return a property value associated with the symbol or `def` if\nmissing.\n\nIf the default value is not supplied and the property is missing,\nan exception will be thrown."  (doc
@@ -195,8 +195,7 @@
 of bounds\nof the string will result in an exception thrown.\n\nIf `end` isn't specified the portion is assumed to begin at `start`\nuntil the end of the original string.\n\nExamples:\n\n    (str-sub \"hello\" 2)\n    ; ↳ \"llo\"\n\n    (str-sub \"hello\" 3 3)\n    ; ↳ \"\"\n\n    (str-sub \"hello\" 2 4)\n    ; ↳ \"ll\""  most-negative-fixnum "A constant integer closest to negative infinity that can be\nrepresented by fixnum type on this particular platform."  memv "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `eqv?`."  max "Return the largest among the arguments.\n\nExamples:\n\n    (max 3 1 9 4)\n    ; ↳ 9\n\n    (max 'c 'h 'z 'a)\n    ; ↳ z\n\n    (max \"t\" \"g\" \"a\")\n    ; ↳ \"t\""  cddadr "Shorthand for (cdr (cdr (car (cdr lst))))."  closure? "Return `T` if the argument is a function that is implemented in LISP\n(as opposed to a C builtin), `NIL` otherwise.\n\nExamples:\n\n    (closure? closure?)\n    ; ↳ T\n\n    (closure? length)\n    ; ↳ NIL"  read-all "Return a list of terms read from the IO object until it ran out of\ndata.\n\nExamples:\n\n    ; read current process' status file on Plan 9\n    (def status (file (str \"/proc/\" (getpid) \"/status\")))\n    (read-all status)\n    ; ↳ (sl glenda Pread 40 0 4940 0 0 0 1856 10 10)"  rand-f64 "Return a random 64-bit floating point number on interval [0.0, 1.0]."  help-print-header "Format and print signature(s) of the term for `(help term)` output."  arg-counts "VM instructions mapped to their expected arguments count."  sleep "Halt the StreetLISP VM for the specified duration of time in seconds.\n\nExamples:\n\n    (sleep 0.1) ; sleep for 100ms"  s16 "Construct a 16-bit signed number."  rune? "Return `T` if the value is a rune, `NIL` otherwise."  os-setenv "Add or replace the value of the environment variable `name` to\n`value`.\n\nIf `value` is `NIL`, the variable is deleted from the environment if\nit exists."  __script "Execute a single file at `path`.\n\nAn unhandled exception will result in it being printed to `*io-err*`\nand the process exiting with a non-zero (non-empty in case OS is Plan\n9) status signaling an error to its parent.")  *doc-extra* #table(append ((:doc-group . list)
   (:doc-see . nconc) (:doc-see . revappend))  io-eof? ((:doc-group . io))  path-exists? ((:doc-group . io)
   (:doc-see . file) (:doc-see . delete-file))  cadddr ((:doc-group . list))  sort ((:doc-group . list)
-represented by fixnum type on this particular platform."  memv "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `eqv?`."  max "Return the largest among the arguments.\n\nExamples:\n\n    (max 3 1 9 4)\n    ; ↳ 9\n\n    (max 'c 'h 'z 'a)\n    ; ↳ z\n\n    (max \"t\" \"g\" \"a\")\n    ; ↳ \"t\""  cddadr "Shorthand for (cdr (cdr (car (cdr lst))))."  closure? "Return `T` if the argument is a function that is implemented in LISP\n(as opposed to a C builtin), `NIL` otherwise.\n\nExamples:\n\n    (closure? closure?)\n    ; ↳ T\n\n    (closure? length)\n    ; ↳ NIL"  read-all "Return a list of terms read from the IO object until it ran out of\ndata.\n\nExamples:\n\n    ; read current process' status file on Plan 9\n    (def status (file (str \"/proc/\" (getpid) \"/status\")))\n    (read-all status)\n    ; ↳ (sl glenda Pread 40 0 4940 0 0 0 1856 10 10)"  rand-f64 "Return a random 64-bit floating point number on interval [0.0, 1.0]."  help-print-header "Format and print signature(s) of the term for `(help term)` output."  arg-counts "VM instructions mapped to their expected arguments count."  sleep "Halt the StreetLISP VM for the specified duration of time in seconds.\n\nExamples:\n\n    (sleep 0.1) ; sleep for 100ms"  s16 "Construct a 16-bit signed number."  rune? "Return `T` if the value is a rune, `NIL` otherwise."  os-setenv "Add or replace the value of the environment variable `name` to\n`value`.\n\nIf `value` is `NIL`, the variable is deleted from the environment if\nit exists."  __script "Execute a single file at `path`.\n\nAn unhandled exception will result in it being printed to `*io-err*`\nand the process exiting with a non-zero (non-empty in case OS is Plan\n9) status signaling an error to its parent.")  *doc-extra* #table(append ((:doc-group . list)
-  (:doc-see . nconc) (:doc-see . revappend))  io-eof? ((:doc-group . io))  path-exists? ((:doc-group . io)
+ve infinity that can be\nrepresented by fixnum type on this particular platform."  memv "Return the tail of a list beginning with the item, or `NIL` otherwise.\nList elements are compared to the `item` using `eqv?`."  max "Return the largest among the arguments.\n\nExamples:\n\n    (max 3 1 9 4)\n    ; ↳ 9\n\n    (max 'c 'h 'z 'a)\n    ; ↳ z\n\n    (max \"t\" \"g\" \"a\")\n    ; ↳ \"t\""  cddadr "Shorthand for (cdr (cdr (car (cdr lst))))."  closure? "Return `T` if the argument is a function that is implemented in LISP\n(as opposed to a C builtin), `NIL` otherwise.\n\nExamples:\n\n    (closure? closure?)\n    ; ↳ T\n\n    (closure? length)\n    ; ↳ NIL"  read-all "Return a list of terms read from the IO object until it ran out of\ndata.\n\nExamples:\n\n    ; read current process' status file on Plan 9\n    (def status (file (str \"/proc/\" (getpid) \"/status\")))\n    (read-all status)\n    ; ↳ (sl glenda Pread 40 0 4940 0 0 0 1856 10 10)"  rand-f64 "Return a random 64-bit floating point number on interval [0.0, 1.0]."  help-print-header "Format and print signature(s) of the term for `(help term)` output."  arg-counts "VM instructions mapped to their expected arguments count."  sleep "Halt the StreetLISP VM for the specified duration of time in seconds.\n\nExamples:\n\n    (sleep 0.1) ; sleep for 100ms"  s16 "Construct a 16-bit signed number."  rune? "Return `T` if the value is a rune, `NIL` otherwise."  os-setenv "Add or replace the value of the environment variable `name` to\n`value`.\n\nIf `value` is `NIL`, the variable is deleted from the environment if\nit exists."  __script "Execute a single file at `path`.\n\nAn unhandled exception will result in it being printed to `*io-err*`\nand the process exiting with a non-zero (non-empty in case OS is Plan\n9) status signaling an error to its parent.")  *doc-extra* #table(append ((:doc-group . list)
 ples:\n\n    (max 3 1 9 4)\n    ; ↳ 9\n\n    (max 'c 'h 'z 'a)\n    ; ↳ z\n\n    (max \"t\" \"g\" \"a\")\n    ; ↳ \"t\""  cddadr "Shorthand for (cdr (cdr (car (cdr lst))))."  closure? "Return `T` if the argument is a function that is implemented in LISP\n(as opposed to a C builtin), `NIL` otherwise.\n\nExamples:\n\n    (closure? closure?)\n    ; ↳ T\n\n    (closure? length)\n    ; ↳ NIL"  read-all "Return a list of terms read from the IO object until it ran out of\ndata.\n\nExamples:\n\n    ; read current process' status file on Plan 9\n    (def status (file (str \"/proc/\" (getpid) \"/status\")))\n    (read-all status)\n    ; ↳ (sl glenda Pread 40 0 4940 0 0 0 1856 10 10)"  rand-f64 "Return a random 64-bit floating point number on interval [0.0, 1.0]."  help-print-header "Format and print signature(s) of the term for `(help term)` output."  arg-counts "VM instructions mapped to their expected arguments count."  sleep "Halt the StreetLISP VM for the specified duration of time in seconds.\n\nExamples:\n\n    (sleep 0.1) ; sleep for 100ms"  s16 "Construct a 16-bit signed number."  rune? "Return `T` if the value is a rune, `NIL` otherwise."  os-setenv "Add or replace the value of the environment variable `name` to\n`value`.\n\nIf `value` is `NIL`, the variable is deleted from the environment if\nit exists."  __script "Execute a single file at `path`.\n\nAn unhandled exception will result in it being printed to `*io-err*`\nand the process exiting with a non-zero (non-empty in case OS is Plan\n9) status signaling an error to its parent.")  *doc-extra* #table(append ((:doc-group . list)
   (:doc-see . nconc) (:doc-see . revappend))  io-eof? ((:doc-group . io))  path-exists? ((:doc-group . io)
   (:doc-see . file) (:doc-see . delete-file))  cadddr ((:doc-group . list))  sort ((:doc-group . list)
@@ -671,12 +670,10 @@
 14823F0767705151488<2851@>079051488<05147:5047:60:" #(#(:kind
   0 NIL NIL :lpad 1 NIL NIL) "" #0# #fn("n1A70_471220RJ600@R00Z3>02324F5151@A07505137026@40272863:" #(void
   princ " ;; [" #fn(type-of) #fn(top-level-value) get-syntax "macro" "???" "]") print-type 9)
-92<F5147260:" #(princ print newline) 7) princ caddr "doc group"
-  print newline) help-print-header 8)
-            identity #fn("n10:" #() identity 4) in-env?
-            #fn("n21B;3F042001<52;J:047101=62:" #(#fn(assq) in-env?) in-env? 7) inlineable? #fn("n10<85B;3t0485<20Q;3i047185T51;3]04727385T52;3O047485T2552S;3@047685T270=5162:" #(λ
-  proper-list? every sym? length> 255 length= #fn(length)) inlineable? 9)
-            io-read-all #fn("n1205021850524228561:" #(#fn(buffer)
+ 9)
+  #fn(for-each) #fn("n170A51471F0P51492<F5147260:" #(princ print newline) 7) princ caddr "doc group"
+  print newline) help-print-header 8)
+            identity #fn("n10:" #() identity 4) in-env?
                            #fn(io-copy)
                                                       #fn(io->str)) io-read-all 8)
             io-read-line #fn("n12002162:" #(#fn(io-read-until) #\newline) io-read-line 7)
--- a/src/docs.sl
+++ b/src/docs.sl
@@ -290,12 +290,6 @@
 (doc-group string
   "Strings and runes.")
 
-(doc-for *whitespace*
-  «The string containing all twenty-five Unicode runes with the property
-   `White_Space=yes`.»
-  :doc-group string
-  :doc-see str-trim)
-
 (doc-for (str . terms)
   «Return concatenation of terms formatted as strings.
 
--- a/src/plan9/lsd.sl
+++ b/src/plan9/lsd.sl
@@ -194,7 +194,7 @@
   (def (readstr loc)
     (unless coref (error "not attached to proc"))
     (io-seek coref loc)
-    (str-trim (io-read-until coref 0) "" "\x00"))
+    (str-trim (io-read-until coref 0) NIL (λ (r) (eq? r #\nul))))
   (if n
       (map 'vec readstr (c-ptr (@ loc) n))
       (readstr (c-ptr (@ loc)))))
--- a/src/str.c
+++ b/src/str.c
@@ -416,5 +416,4 @@
 void
 str_init(void)
 {
-	setc(mk_csym("*whitespace*"), cvalue_static_cstr((const char*)ws));
 }
--- a/src/system.sl
+++ b/src/system.sl
@@ -2036,37 +2036,43 @@
 
 ;;; string functions
 
-(def (str-trim s (at-start *whitespace*) (at-end at-start))
-  «Return the portion of the string with all leading runes in `at-start`
-   and/or trailing runes in `at-end` removed.
+(def (str-trim s (lead-pred rune-whitespace?) (trail-pred lead-pred))
+  «Return the portion of the string with all leading runes satisfying
+   `lead-pred` (and trailing runes satisfying `trail-pred`) removed.
 
-   Without runes to remove specified, `str-trim` will remove whitespace
-   (defined as `*whitespace*`) from both sides of the string.
+   Without predicates explicitly specified, `str-trim` will remove
+   whitespace from both sides of the string.
 
+   Pass `NIL` as the predicate to disable trimming on either side.
+
    Examples:
 
        (str-trim " \nhello\t\v")
        ; ↳ "hello"
 
-       (str-trim " \nhello\t\v" " \v")
+       (str-trim " \nhello\t\v"
+                 (λ (r) (str-find " \v" r)))
        ; ↳ "\nhello\t"
 
-       (str-trim "123abcdef456" "13" "46")
-       ; ↳ "23abcdef45"»
+       (str-trim "123abc!456def"
+                 rune-numeric?
+                 rune-alphabetic?)
+       ; ↳ "abc!456"»
   :doc-group string
-  :doc-see *whitespace*
-  (def (trim-start s runes i L)
-    (if (and (< i L) (str-find runes (str-rune s i)))
-        (trim-start s runes (1+ i) L)
+  :doc-see str-sub
+  :doc-see str-map
+  (def (trim-start i L)
+    (if (and (< i L) (lead-pred (str-rune s i)))
+        (trim-start (1+ i) L)
         i))
-  (def (trim-end s runes i)
-    (if (and (> i 0) (str-find runes (str-rune s (1- i))))
-        (trim-end s runes (1- i))
+  (def (trim-end i)
+    (if (and (> i 0) (trail-pred (str-rune s (1- i))))
+        (trim-end (1- i))
         i))
   (let ((L (length s)))
     (str-sub s
-             (trim-start s at-start 0 L)
-             (trim-end   s at-end   L))))
+             (if lead-pred (trim-start 0 L) 0)
+             (if trail-pred (trim-end L) L))))
 
 (def (str-map fn s)
   «Return the concatenation of the values produced by `fn` when applying
--- a/test/unittest.sl
+++ b/test/unittest.sl
@@ -1044,9 +1044,9 @@
 (assert (equal? (delete-duplicates '(a 0 b c1 a b 3 c 5))
                                    '(a 0 b c1     3 c 5)))
 
-(assert (equal? (str-trim "1λ1 hello 1λ11" "" "1 λ") "1λ1 hello"))
-(assert (equal? (str-trim "1λ1 hello 1λ11" "1 λ" "") "hello 1λ11"))
-(assert (equal? (str-trim "1λ1 hello 1λ11" "1 λ") "hello"))
+(assert (equal? (str-trim "1λ1 hello 1λ11" NIL (λ (r) (str-find "1 λ" r))) "1λ1 hello"))
+(assert (equal? (str-trim "1λ1 hello 1λ11" (λ (r) (str-find "1 λ" r)) NIL) "hello 1λ11"))
+(assert (equal? (str-trim "1λ1 hello 1λ11" (λ (r) (str-find "1 λ" r))) "hello"))
 (assert (equal? (str-trim " \t\nhello\v\f\r") "hello"))
 
 (assert (rune #xd7ff))
--