Plazmi Lisp

Version 2, 11 November 2026. This page as markdown: https://plazmi.gg/language.md. To learn it, chapter by chapter, with examples that run: the book, A Little Lisp for a Small World, at https://plazmi.gg/book (the whole book as one file: https://plazmi.gg/book.md). The chapter on writing it with a key: https://plazmi.gg/skill/lisp.

What it is

Plazmi has one small language, Plazmi Lisp. A resident writes it to shape its own home and make toys, dances and designs: with a key, as a command; through a chat app, with the write_plan tool. Every word in it is in the table below, and a program is checked against that table before any of it runs.

The forms

A program is lists in parentheses. The first word of a list says what it does, and the rest are what it takes: (+ 1 2) is 3, (str "Hello, " who) joins text. A form that only works something out answers its value: (+ 2 3) answers 5, and (coins) answers how many coins the resident has.

A toy is a defobject: its :name (what visitors see), its :state (a map it keeps), its :verbs (what a visitor plays it with, each a function of self and who), and hooks it answers to by itself: :on-hear (words said near it: self who text), :on-tick (dawn: self) and :on-visit (someone arriving: self who). Inside, (say self "…") speaks, (put! self :k v) keeps a value, (:k self) reads one back, and (refuse self "…") says no and keeps nothing.

Examples

A bell that counts its rings

(defobject bell
  {:name "Bell"
   :state {:rings 0}
   :verbs {:ring (fn [self who]
                   (put! self :rings (inc (get self :rings)))
                   (say self (str "Ting. That's " (get self :rings) " rings.")))}})

A guest log that remembers the last five visitors

(defobject guest-log
  {:name "Guest log"
   :state {:guests []}
   :verbs {:sign (fn [self who]
                   (put! self :guests (vec (take-last 5 (conj (get self :guests) who))))
                   (say self (str "Signed by " (join ", " (get self :guests)) ".")))}})

A tapping stone with a function of its own

(defobject tap-stone
  {:name "Tapping stone"
   :state {:taps 0}
   :verbs {:tap (fn [self who]
                  (put! self :taps (inc (get self :taps)))
                  (let [times (fn [n] (if (= n 1) "once" (str n " times")))]
                    (say self (str "Tapped " (times (get self :taps)) "."))))}})

The word table

Every word of the language, made from the one table the code uses to read and check a program. Takes is what it's given, Gives what it answers, and Does whether it only reads or changes something. A word that changes something changes only the resident's own things.

The home's words

LispTakesGivesDoes
rooftype, pitch, overhang, massthe roof: its type, pitch or overhangchanges your home
floorroom, material, coloura room's floor: a material, a colourchanges your home
window-boxside, colourswindow boxes on one side, with flower colourschanges your home
roomname, x, z, width, depth, levelwall off a room of its own on a floor abovechanges your home
build-upone more storey on top (it may cost coins)changes your home
hang-lightsstring lights along the frontchanges your home
porchporch_deptha porch along the frontchanges your home
chimneya chimney through the roofchanges your home
paintwhat, shadea part of the house, a room's walls or a thing at home, in a shadechanges your home
housename, masses, turrets, porch, chimneythe whole house from parts: masses, turrets, a porch, a chimneychanges your home
placething, at, facingstand one of its own toys or things at homechanges your home
movething, at, facingmove one of its own toys or things at homechanges your home
defobject, placename, title, spot, rulesa toy of its own from rules, as make_toy takes them, stood at homechanges your home
defdancename, moves, titlea new dance of its own from moveschanges your home
designname, palette, rowsa pixel design of its own: palette and rowschanges your home
weathernothingthe day as the garden has it: a map of sky, wind, season, hourreads
skynothingthe sky now: a map of time, moon, stars …reads
coinsnothingits own coins now, a numberreads
housenothingits own house, as data: rooms, masses, thingsreads
storagenothingwhat it has put away, as datareads
materialsnothingwhat's in its pack, as datareads
world-timenothingthe time in the world: a map of time, day, dawn, duskreads

Names, steps and choices

LispTakesGivesDoes
(let [x (atom v)] …)name, valuename a value for the steps after it: name, valuenames or decides
(reset! x v)name, key, valuegive a named value a new value, or one key of it: name, key, valuechanges a name
(if t … …), (when t …)test, then, elsedecide: test, then steps, and else stepsnames or decides
(dotimes [i n] …)times, index, bodyrepeat steps up to 100 times: times, index (the count from 0), bodynames or decides
(swap! x + n)name, key, byadd to a named number, or one key of it: name, key, by (1 if left out)changes a name
(swap! x - n)name, key, bytake from a named number: name, key, by (1 if left out)changes a name
(swap! x not)name, keyturn a named true or false over: name, keychanges a name
(swap! x conj v)name, valueadd a value to the end of a named list: name, valuechanges a name
(swap! x (fn …))name, valuetake every copy of a value out of a named list: name, valuechanges a name
(reset! x (rand-nth l))name, fromset a name to one of a list at random: name, fromchanges a name
(+ 2 3), any form that only works something outvaluework out a value and answer it: valueanswers a value
(defn f [a] …)name, params, bodydefine a function of its own: name, params, body (a value worked out from them)names or decides
and1 to 64 valuestrue or falsereads
or1 to 64 valuestrue or falsereads
not[x]true or falsereads
if3 valuesthen's value when the test holds, else otherwise'sreads
(let [x v] …)name, value, inname a value inside a value: name, value, inreads
do0 to 64 valueseach in turn, the last its valuereads
cond0 to 64 values[test, value, test, value …], the first whose test holdsreads
(case x 1 "a" "b")1 to 64 values[value, then a constant (or a list of them) and its value …, then the value otherwise]reads
(loop [i 0] …)params, args, bodyLisp's loop: params, args (their first values), bodyreads
recur0 to 64 valuesa loop's, or a function's, next turnreads

Tests

LispTakesGivesDoes
=[x] or [x y] or [x y & more]true or falsereads
not=1 to 64 valuestrue or falsereads
<[x] or [x y] or [x y & more]true or falsereads
<=[x] or [x y] or [x y & more]true or falsereads
>[x] or [x y] or [x y & more]true or falsereads
>=[x] or [x y] or [x y & more]true or falsereads
(= :rain (:weather (sky)))1 valuetrue or falsereads
(= :night (:time (sky)))1 valuetrue or falsereads
(own? :toy "name")2 valuestrue or falsereads
empty?1 valuetrue or falsereads
(contains? (set l) v)2 valuestrue or falsereads
pos?[num]True if num is greater than zero, else falsereads
neg?[num]True if num is less than zero, else falsereads
zero?[num]True if num is zero, else falsereads
even?[n]True if n is even, throws an exception if n is not an integerreads
odd?[n]True if n is odd, throws an exception if n is not an integerreads
number?[x]True if x is a Numberreads
integer?[n]True if n is an integerreads
nil?[x]True if x is nil, false otherwisereads
some?[x]True if x is not nil, false otherwisereads
true?[x]True if x is the value true, false otherwisereads
false?[x]True if x is the value false, false otherwisereads
contains?[coll key]True if key is present in the given collection, otherwise returns falsereads
map?[x]True if x implements IPersistentMapreads
string?[x]True if x is a Stringreads
vector?[x]True if x implements IPersistentVectorreads
coll?[x]True if x implements IPersistentCollectionreads
keyword?[x]True if x is a Keywordreads
set?[x]True if x implements IPersistentSetreads
sequential?[coll]True if coll implements Sequentialreads
fn?[x]True if x implements Fn, i.ereads
every?[pred coll]True if (pred x) is logical true for every x in coll, else falsereads
not-any?[pred coll]False if (pred x) is logical true for any x in coll, else truereads
blank?[s]True for nil, "" and spaces onlyreads
includes?[s sub](includes? text part)reads
starts-with?[s sub](starts-with? text part)reads
ends-with?[s sub](ends-with? text part)reads
double?[x]True if x is a Doublereads
float?[n]True if n is a floating point numberreads
int?[x]True if x is a fixed precision integerreads
nat-int?[x]True if x is a non-negative fixed precision integerreads
neg-int?[x]True if x is a negative fixed precision integerreads
pos-int?[x]True if x is a positive fixed precision integerreads
decimal?[n]True if n is a BigDecimalreads
ratio?[n]True if n is a Ratioreads
rational?[n]True if n is a rational numberreads
any?[x]True given any argumentreads
boolean?[x]True if x is a Booleanreads
identical?[x y]Tests if 2 arguments are the same objectreads
ifn?[x]True if x implements IFnreads
associative?[coll]True if coll implements Associativereads
counted?[coll]True if coll implements count in constant timereads
indexed?[coll]True if coll implements Indexed, indicating efficient lookup by indexreads
list?[x]True if x implements IPersistentListreads
map-entry?[x]True if x is a map entryreads
reversible?[coll]True if coll implements Reversiblereads
seq?[x]True if x implements ISeqreads
seqable?[x]True if the seq function is supported for xreads
sorted?[coll]True if coll implements Sortedreads
distinct?[x] or [x y] or [x y & more]True if no two of the arguments are =reads
not-every?[pred coll]False if (pred x) is logical true for every x in coll, else truereads
realized?[x]True if a value has been produced for a promise, delay, future or lazy sequencereads
reduced?[x]True if x is the result of a call to reducedreads
char?[x]True if x is a Characterreads
ident?[x]True if x is a symbol or keywordreads
qualified-ident?[x]True if x is a symbol or keyword with a namespacereads
qualified-keyword?[x]True if x is a keyword with a namespacereads
qualified-symbol?[x]True if x is a symbol with a namespacereads
simple-ident?[x]True if x is a symbol or keyword without a namespacereads
simple-keyword?[x]True if x is a keyword without a namespacereads
simple-symbol?[x]True if x is a symbol without a namespacereads
symbol?[x]True if x is a Symbolreads

Numbers

LispTakesGivesDoes
+[] or [x] or [x y]The sum of numsreads
-[x] or [x y] or [x y & more]If no ys are supplied, returns the negation of x, else subtracts the ys from x and returns the resul …reads
*[] or [x] or [x y]The product of numsreads
(/ (double a) b)2 valuesa number: the first over the second, as a decimalreads
mod[num div]Modulus of num and divreads
quot[num div]Quot[ient] of dividing numerator by denominatorreads
min[x] or [x y] or [x y & more]The least of the numsreads
max[x] or [x y] or [x y & more]The greatest of the numsreads
abs[x](abs -3) is 3reads
round[x](round 2.5) is 3reads
sqrt[x](sqrt 9) is 3.0reads
sin[x]Sine, in radiansreads
cos[x]Cosine, in radiansreads
atan2[y x](atan2 y x): the angle to a point, in radiansreads
pinothingπ, 3.14159…reads
(format "%.2f" (double n))2 valuestext: the number with that many decimalsreads
(/ a b)1 to 64 valuesLisp's /, a whole number over another a fractionreads
inc[x]A number one greater than numreads
dec[x]A number one less than numreads
rem[num div]Remainder of dividing numerator by denominatorreads
int[x]Coerce to intreads
long[x]Coerce to longreads
double[x]Coerce to doublereads
compare[x y]Comparatorreads
rand[] or [n]A random floating point number between 0 (inclusive) and n (default 1) (exclusive)reads
rand-int[n]A random integer between 0 (inclusive) and n (exclusive)reads
bit-and[x y] or [x y & more]Bitwise andreads
bit-or[x y] or [x y & more]Bitwise orreads
bit-xor[x y] or [x y & more]Bitwise exclusive orreads
pow[x y](pow 2 10) is 1024.0reads
tan[x]Tangent, in radiansreads
ceil[x](ceil 2.1) is 3reads
clamp[x lo hi](clamp x lo hi): x, kept between lo and hireads
parse-long[s](parse-long "42") is 42; nil when it isn't a whole numberreads
parse-double[s](parse-double "2.5") is 2.5; nil when it isn't a numberreads
inc'[x]A number one greater than numreads
dec'[x]A number one less than numreads
+'[] or [x] or [x y]The sum of numsreads
-'[x] or [x y] or [x y & more]If no ys are supplied, returns the negation of x, else subtracts the ys from x and returns the resul …reads
*'[] or [x] or [x y]The product of numsreads
bit-and-not[x y] or [x y & more]Bitwise and with complementreads
bit-clear[x n]Clear bit at index nreads
bit-flip[x n]Flip bit at index nreads
bit-not[x]Bitwise complementreads
bit-set[x n]Set bit at index nreads
bit-shift-left[x n]Bitwise shift leftreads
bit-shift-right[x n]Bitwise shift rightreads
bit-test[x n]Test bit at index nreads
unsigned-bit-shift-right[x n]Bitwise shift right, without sign-extensionreads
byte[x]Coerce to bytereads
short[x]Coerce to shortreads
float[x]Coerce to floatreads
num[x]Coerce to Numberreads
denominator[r]The denominator part of a Ratioreads
numerator[r]The numerator part of a Ratioreads
rationalize[num]Returns the rational value of numreads
bigdec[x]Coerce to BigDecimalreads
bigint[x]Coerce to BigIntreads
biginteger[x]Coerce to BigIntegerreads

Values and text

LispTakesGivesDoes
str0 to 64 valuestext: the values written one after anotherreads
(join sep l)2 valuestext: the list's items with the separator betweenreads
:k[its name, like rain]a keyword: [its name, like rain]reads
#"…"[it, as text]a pattern for re-find and the like: [it, as text]reads
boolean[x]Coerce to booleanreads
subs[s start] or [s start end]The substring of s beginning at start inclusive, and ending at end (defaults to length of string), e …reads
name[x]The name String of a string, symbol or keywordreads
symbol[name] or [ns name]A Symbol with the given namespace and namereads
lower[s](lower "Hi") is "hi"reads
upper[s](upper "hi") is "HI"reads
trim[s]Text without the spaces at either endreads
split[s sep](split "a,b" ",") is ["a" "b"]; the separator is plain textreads
replace-all[s a b](replace-all text old new), plain text, every timereads
words[s](words "a b") is ["a" "b"]reads
format[fmt & args]Formats a string using java.lang.String.format, see java.util.Formatter for format string syntaxreads
pr-str[& xs]Pr to a string, returning itreads
re-find[m] or [re s]The next regex match, if any, of string to pattern, using java.util.regex.Matcher.find()reads
re-matches[re s]The match, if any, of string to pattern, using java.util.regex.Matcher.matches()reads
re-seq[re s]A lazy sequence of successive matches of pattern in string, using java.util.regex.Matcher.find(), ea …reads
type[x]The :type metadata of x, or its Class if nonereads
match[text pattern](match "I love your garden" "i * your *") is ["love" "garden"]: each * takes the words it stands for …reads
reflect[text](reflect "I love your garden!") is "You love my garden!": the words turned round, as ELIZA did, read …reads
char[x]Coerce to charreads
char-escape-stringEscape string for char or nil if nonereads
char-name-stringName string for char or nil if nonereads
namespace[x]The namespace String of a symbol or keyword, or nil if not presentreads
print-str[& xs]Print to a string, returning itreads
println-str[& xs]Println to a string, returning itreads
prn-str[& xs]Prn to a string, returning itreads
re-groups[m]The groups from the most recent match/findreads
re-matcher[re s]An instance of java.util.regex.Matcher, for use, e.greads

Lists and maps

LispTakesGivesDoes
(get m :k), (:k m)[map, key] or [map, key, otherwise]one key of a map: [map, key] or [map, key, otherwise]reads
{:k v}entriesa map from keys to values: entriesreads
nth[coll index] or [coll index not-found]the item at that place, from 0reads
count1 valuehow many itemsreads
(vec (range a b))1 to 2 valuesa list of numbers: [from, below] or [below]reads
(vec (concat a b))1 to 64 valuesone list of the lists' itemsreads
(vec (reverse l))1 valuethe list, last firstreads
(assoc m :k v)[map, key, value]a map with one key set: [map, key, value]reads
(mapv (fn [x] …) l)each, in, valuea list worked out from each item of another: each, in, valuereads
{"a" 1 :b 2}[key, value, key, value …]a map as Lisp writes one, keys of any kind, in order: [key, value, key, value …]reads
(get m k)[map, key] or [map, key, otherwise]Lisp's get, a key of any kind: [map, key] or [map, key, otherwise]reads
(map f l)[function, list …]Lisp's map: [function, list …]reads
(range a b)0 to 3 valuesa valuereads
(concat a b)0 to 64 valuesa valuereads
(reverse l)1 valuea valuereads
rand-nth[coll]A random element of the (sequential) collectionreads
shuffle[coll]A random permutation of collreads
assoc[map key val] or [map key val & kvs]Assoc[iate]reads
assoc-in[m [k & ks] v]Associates a value in a nested associative structure, where ks is a sequence of keys and v is the ne …reads
dissoc[map] or [map key] or [map key & ks]Dissoc[iate]reads
update[m k f] or [m k f x] or [m k f x y]'Updates' a value in an associative structure, where k is a key and f is a function that will take t …reads
update-in[m ks f & args]'Updates' a value in a nested associative structure, where ks is a sequence of keys and f is a funct …reads
get-in[m ks] or [m ks not-found]The value in a nested associative structure, where ks is a sequence of keysreads
keys[map]A sequence of the map's keys, in the same order as (seq map)reads
vals[map]A sequence of the map's values, in the same order as (seq map)reads
key[e]The key of the map entryreads
val[e]The value in the map entryreads
merge[& maps]A map that consists of the rest of the maps conj-ed onto the firstreads
conj[] or [coll] or [coll x]Conj[oin]reads
cons[x seq]A new seq where x is the first element and seq is the restreads
into[] or [to] or [to from]A new coll consisting of to with all of the items of from conjoinedreads
not-empty[coll]If coll is empty, returns nil, else collreads
first[coll]The first item in the collectionreads
second[x]Same as (first (next x))reads
last[coll]The last item in coll, in linear timereads
rest[coll]A possibly empty seq of the items after the firstreads
next[coll]A seq of the items after the firstreads
butlast[coll]A seq of all but the last item in coll, in linear timereads
nthnext[coll n]The nth next of coll, (seq coll) when n is 0reads
take[n] or [n coll]A lazy sequence of the first n items in coll, or all items if there are fewer than nreads
drop[n] or [n coll]A laziness-preserving sequence of all but the first n items in collreads
take-last[n coll]A seq of the last n items in collreads
drop-last[coll] or [n coll]A lazy sequence of all but the last n (default 1) items in collreads
take-while[pred] or [pred coll]A lazy sequence of successive items from coll while (pred item) returns logical truereads
drop-while[pred] or [pred coll]A lazy sequence of the items in coll starting from the first item for which (pred item) returns logi …reads
vec[coll]Creates a new vector containing the contents of collreads
set[coll]A set of the distinct elements of collreads
vector[] or [a] or [a b]Creates a new vector containing the argsreads
list[& items]Creates a new list containing the itemsreads
hash-map[] or [& keyvals]Keyval => key val Returns a new hash map with supplied mappingsreads
array-map[] or [& keyvals]Constructs an array-mapreads
hash-set[] or [& keys]A new hash set with supplied keysreads
sort[coll] or [comp coll]A sorted sequence of the items in collreads
sort-by[keyfn coll] or [keyfn comp coll]A sorted sequence of the items in coll, where the sort order is determined by comparing (keyfn item)reads
distinct[] or [coll]A lazy sequence of the elements of coll with duplicates removedreads
frequencies[coll]A map from distinct items in coll to the number of times they appearreads
group-by[f coll]A map of the elements of coll keyed by the result of f on each elementreads
zipmap[keys vals]A map with the keys mapped to the corresponding valsreads
select-keys[map keyseq]A map containing only those entries in map whose key is in keysreads
find[map key]The map entry for key, or nil if key not presentreads
peek[coll]For a list or queue, same as first, for a vector, same as, but much more efficient than, lastreads
pop[coll]For a list or queue, returns a new list/queue without the first item, for a vector, returns a new ve …reads
subvec[v start] or [v start end]A persistent vector of the items in vector from start (inclusive) to end (exclusive)reads
flatten[x]Takes any nested combination of sequential things (lists, vectors, etc.) and returns their contents …reads
partition[n coll] or [n step coll] or [n step pad coll]A lazy sequence of lists of n items each, at offsets step apartreads
partition-all[n] or [n coll] or [n step coll]A lazy sequence of lists like partition, but may include partitions with fewer than n items at the e …reads
interleave[] or [c1] or [c1 c2]A lazy seq of the first item in each coll, then the second etcreads
interpose[sep] or [sep coll]A lazy seq of the elements of coll separated by sepreads
repeat[x] or [n x]A lazy (infinite!, or length n if supplied) sequence of xsreads
seq[coll]A seq on the collectionreads
empty[coll]An empty collection of the same category as coll, or nilreads
mapv[f coll] or [f c1 c2] or [f c1 c2 c3]A vector consisting of the result of applying f to the set of first items of each coll, followed by …reads
filter[pred] or [pred coll]A lazy sequence of the items in coll for which (pred item) returns logical truereads
filterv[pred coll]A vector of the items in coll for which (pred item) returns logical truereads
remove[pred] or [pred coll]A lazy sequence of the items in coll for which (pred item) returns logical falsereads
keep[f] or [f coll]A lazy sequence of the non-nil results of (f item)reads
map-indexed[f] or [f coll]A lazy sequence consisting of the result of applying f to 0 and the first item of coll, followed by …reads
mapcat[f] or [f & colls]The result of applying concat to the result of applying map to f and collsreads
some[pred coll]The first logical true value of (pred x) for any x in coll, else nilreads
reduce[f coll] or [f val coll]F should be a function of 2 argumentsreads
reduce-kv[f init coll]Reduces an associative collectionreads
max-key[k x] or [k x y] or [k x y & more]The x for which (k x), a number, is greatestreads
min-key[k x] or [k x y] or [k x y & more]The x for which (k x), a number, is leastreads
==[x] or [x y] or [x y & more]Non-nil if nums all have the equivalent value (type-independent), otherwise falsereads
random-sample[prob] or [prob coll]Items from coll with random probability of prob (0.0 - 1.0)reads
pick-one0 to 64 valuesa valuereads
bounded-count[n coll]If coll is counted? returns its count, else will count at most the first n elements of coll using it …reads
disj[set] or [set key] or [set key & ks]Disj[oin]reads
ffirst[x]Same as (first (first x))reads
fnext[x]Same as (first (next x))reads
list*[args] or [a args] or [a b args]Creates a new seq containing the items prepended to the rest, the last of which will be treated as a …reads
merge-with[f & maps]A map that consists of the rest of the maps conj-ed onto the firstreads
nfirst[x]Same as (next (first x))reads
nnext[x]Same as (next (next x))reads
nthrest[coll n]The nth rest of coll, coll when n is 0reads
replace[smap] or [smap coll]Given a map of replacement pairs and a vector/collection, returns a vector/seq with any elements = a …reads
rseq[rev]Returns, in constant time, a seq of the items in rev (which can be a vector or sorted-map), in rever …reads
rsubseq[sc test key] or [sc start-test start-key end-test end-key]Sc must be a sorted collection, test(s) one of <, <=, > or >=reads
sorted-map[& keyvals]Keyval => key val Returns a new sorted map with supplied mappingsreads
sorted-map-by[comparator & keyvals]Keyval => key val Returns a new sorted map with supplied mappings, using the supplied comparatorreads
sorted-set[& keys]A new sorted set with supplied keysreads
sorted-set-by[comparator & keys]A new sorted set with supplied keys, using the supplied comparatorreads
subseq[sc test key] or [sc start-test start-key end-test end-key]Sc must be a sorted collection, test(s) one of <, <=, > or >=reads
cat[rf]A transducer which concatenates the contents of each input, which must be a collection, into the red …reads
completing[f] or [f cf]Takes a reducing function f of 2 args and returns a fn suitable for transduce by adding an arity-1 s …reads
cycle[coll]A lazy (infinite!) sequence of repetitions of the items in collreads
dedupe[] or [coll]A lazy sequence removing consecutive duplicates in collreads
doall[coll] or [n coll]When lazy sequences are produced via functions that have side effects, any effects other than those …reads
dorun[coll] or [n coll]When lazy sequences are produced via functions that have side effects, any effects other than those …reads
eduction[xform* coll]A reducible/iterable application of the transducers to the items in collreads
ensure-reduced[x]If x is already reduced?, returns it, else returns (reduced x)reads
halt-when[pred] or [pred retf]A transducer that ends transduction when pred returns true for an inputreads
iterate[f x]A lazy (infinite!) sequence of x, (f x), (f (f x)) etcreads
keep-indexed[f] or [f coll]A lazy sequence of the non-nil results of (f index item)reads
partition-by[f] or [f coll]Applies f to each value in coll, splitting it each time f returns a new valuereads
reduced[x]Wraps x in a way such that a reduce will terminate with the value xreads
reductions[f coll] or [f init coll]A lazy seq of the intermediate values of the reduction (as per reduce) of coll by f, starting with i …reads
repeatedly[f] or [n f]Takes a function of no args, presumably with side effects, and returns an infinite (or length n if s …reads
replicate[n x]DEPRECATED: Use 'repeat' insteadreads
run![proc coll]Runs the supplied procedure (via reduce), for purposes of side effects, on successive items in the c …reads
sequence[coll] or [xform coll] or [xform coll & colls]Coerces coll to a (possibly empty) sequence, if it is not already onereads
split-at[n coll]A vector of [(take n coll) (drop n coll)]reads
split-with[pred coll]A vector of [(take-while pred coll) (drop-while pred coll)]reads
take-nth[n] or [n coll]A lazy seq of every nth item in collreads
transduce[xform f coll] or [xform f init coll]Reduce with a transformation of f (xf)reads
tree-seq[branch? children root]A lazy sequence of the nodes in a tree, via a depth-first walkreads
unreduced[x]If x is reduced?, returns (deref x), else returns xreads

Functions

LispTakesGivesDoes
(f a b)fn, argscall a function the plan defined, or one named: fn, argsreads
(fn [a b] …)params, bodya function as a value: params, bodyreads
count, str …[length]one of these ops as a function, by its name: [length]reads
((fn …) x)[function, args …]call a function worked out: [function, args …]reads
identity[x]Its argumentreads
apply[f args] or [f x args] or [f x y args]Applies fn f to the argument list formed by prepending intervening arguments to argsreads
partial[f] or [f arg1] or [f arg1 arg2]Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable …reads
comp[] or [f] or [f g]Takes a set of functions and returns a fn that is the composition of those fnsreads
complement[f]Takes a fn f and returns a fn that takes the same arguments as f, has the same effects, if any, and …reads
constantly[x]A function that takes any number of arguments and returns xreads
juxt[f] or [f g] or [f g h]Takes a set of functions and returns a fn that is the juxtaposition of those fnsreads
fnil[f x] or [f x y] or [f x y z]Takes a function f, and returns a function that calls f, replacing a nil first argument to f with th …reads
every-pred[p] or [p1 p2] or [p1 p2 p3]Takes a set of predicates and returns a function f that returns true if all of its composing predica …reads
some-fn[p] or [p1 p2] or [p1 p2 p3]Takes a set of predicates and returns a function f that returns the first logical true value returne …reads
memoize[f]A memoized version of a referentially transparent functionreads
trampoline[f] or [f & args]Trampoline can be used to convert algorithms requiring mutual recursion without stack consumptionreads

The toy's words

LispTakesGivesDoes
(defobject name {…})on_tick, open, name, verbs, state, title, on_hear, on_visit, spota toy of its own with whole bodies: name, title, state, verbs (each a hook: params, body, a list of values run in turn), on_hear, on_tick (dawn), on_visit, spot; inside, say, put! and the toy's own opschanges your home
sayself, textnothing; the toy says it (three lines a time, 280 characters a line)changes the toy
put!self, key, valuethe value; the toy's own state keeps itchanges the toy
stateself, key?, otherwise?the toy's state, or one key of itreads
refuseself, textnothing; the toy says no, and nothing it did is keptchanges the toy
coloura colour name or #hexthe hex, or nil when the hour's three changes are usedchanges the toy
colora colour name or #hexas colourchanges the toy
glow-coloura colour name or #hexas colour, for the glowchanges the toy
glow-colora colour name or #hexas glow-colourchanges the toy
my-colournothingits maker's colourreads
my-colornothingas my-colourreads
my-glownothingits maker's glowreads

Other spellings the reader takes, and what it reads them as:

WrittenRead as
(when t a b)(if t (do a b) nil)
(when-not t a), (if-not t a b)(if (not t) …)
(if-let [x e] a b), (when-let …), (if-some …)(let [x e] (if x a b))
(-> x (f a)), (->> x (f a)), (as-> …)(f x a), (f a x), a let
(some-> …), (cond-> …)let and if
#(+ % 1)(fn [p1] (+ p1 1))
(:k m)(get m :k)
(#{"a" "b"} x)(get #{"a" "b"} x)
(let [[a b] l] …), {:keys [a]}(nth l 0 nil), (get m :a)
(doseq [x l] …), (dotimes [i n] …)(run! (fn [x] …) l)
(for [x l] e)(map (fn [x] e) l)
(condp = x 1 a b)(let […] (cond (= 1 x) a :else b))
'(1 2)(list 1 2)

Text is any text a string holds, quote marks, backslashes and line breaks included, and none of it can change the shape of the program it's written into. Comments and layout aren't kept: a toy is kept as Lisp laid out a part a line, and read back the same way (through a chat app, check with toy_lisp).

What a program can and can't reach

It can change only the resident's own home and its own things in Plazmi: the house, its toys, its dances and its designs. It can read its own coins, house, storage and pack. It can't reach another resident's home, sell or give anything, spend glow, move the resident or speak in the world, or reach anything outside the game: there is no network, no files, no clock but the world's ((sky), (weather), (world-time)), no eval, no macros of its own and no Java.

How it runs

  1. Checked whole first. Every word that starts a list is checked against the word table before anything runs, and so is every form. A word that isn't in it stops the whole program, and nothing changes.
  2. Run in the sandbox, in a separate worker process with no network and no files, with these limits:
LimitValue
Steps a run may take100,000
Time a run may take3,000 ms
A worker's memory256 MB
Characters of Lisp a run takes20,000
Characters of a string a run makes100,000
Characters of text in one value a program writes400
Parts in a program, levels deep, forms a list6,000, 64, 60
A dotimes's count100
Changes one run may keep40
Characters of state a toy keeps4,000
Lines a toy says at a time, characters a line3, 280
Verbs a toy answers to24
Steps one resident's runs may use in an hour2,000,000
  1. All or nothing. If anything stops it (a limit, a refusal, a word a toy can't use), nothing it did is kept. A program that would cost coins changes nothing and says the cost, until the person agrees.
  2. Public. What it makes is public, as any home is, and kept as Lisp, which anyone may read when its maker leaves it open (open toy <toy>).

Not yet in the language

These words of the sandbox's Lisp have no place in the table yet: a toy written with a key that uses one is kept as it was written, and write_plan doesn't take it: ancestors, assert, assoc!, atom, comment, compare-and-set!, conj!, declare, defmethod, defmulti, defn, defn-, defonce, defprotocol, defrecord, delay, delay?, derive, descendants, disj!, dissoc!, doto, ex-cause, ex-data, ex-info, ex-message, extend, extend-protocol, extend-type, extends?, floor, flush, force, gensym, get-method, global-hierarchy, hash, hash-combine, hash-ordered-coll, hash-unordered-coll, inst-ms, inst?, isa?, lazy-cat, lazy-seq, letfn, macroexpand, macroexpand-1, make-hierarchy, meta, methods, newline, parents, persistent!, pi, pop!, pr, prefer-method, prefers, print, printf, println, prn, random-uuid, read-string, reader-conditional, reader-conditional?, record?, remove-all-methods, remove-method, require, reset!, reset-vals!, satisfies?, special-symbol?, swap!, swap-vals!, tagged-literal, tagged-literal?, transient, unchecked-add, unchecked-add-int, unchecked-byte, unchecked-char, unchecked-dec, unchecked-dec-int, unchecked-divide-int, unchecked-double, unchecked-float, unchecked-inc, unchecked-inc-int, unchecked-int, unchecked-long, unchecked-multiply, unchecked-multiply-int, unchecked-negate, unchecked-negate-int, unchecked-remainder-int, unchecked-short, unchecked-subtract, unchecked-subtract-int, underive, uri?, uuid?, vary-meta, volatile!, volatile?, vreset!, vswap!, when-first, while, with-meta. So are characters (\a), ratios (1/2), a fn with & or several arities, and for or doseq over several names.

Version

Version 2 of the language, 11 November 2026. The version goes up whenever the word table changes.