Part I. The language · this page as markdown
Text, lists and maps
Most of what a toy says is text, and most of what it remembers is a list or a map. This chapter is a tour of the words for each. You don't need to learn them all at once: read it through, and come back when you need one.
Text #
str joins values into text, writing each as a person would read it. count says how many characters a text has, and subs takes part of it, counting from 0:
(str "Ting" "." " " 3 " rings")
(count "garden")
(subs "garden" 0 3)
(subs "garden gate" 7)"Ting. 3 rings"
6
"gar"
"gate"(subs t a b) is the characters from place a up to, not including, place b; with no b, to the end.
These words change or test text. Each answers a new text, or true or false:
(upper "ting")
(lower "Hello, Bell")
(trim " hello ")
(includes? "a lovely garden" "garden")
(starts-with? "garden gate" "garden")
(ends-with? "garden gate" "gate")
(blank? " ")
(replace-all "a-b-c" "-" " ")"TING"
"hello, bell"
"hello"
true
true
true
true
"a b c"replace-all replaces every copy of plain text: the second text is never a pattern.
Text into lists, and back #
words splits text at its spaces, split at any plain text you give, and join puts a list back together with a separator between:
(words "the lavender came up")
(split "rose,sage,moss" ",")
(join ", " ["rose" "sage" "moss"])
(join " · " [1 2 3])["the" "lavender" "came" "up"]
["rose" "sage" "moss"]
"rose, sage, moss"
"1 · 2 · 3"join takes the separator first and the list second.
Numbers in text #
format writes numbers into text by a pattern: %s for any value, %d for a whole number, and %.2f for a decimal with two places. parse-long and parse-double read a number out of text, and answer nil when the text isn't one:
(format "%d rings" 3)
(format "%s and %s" "rose" "sage")
(format "%.2f metres" 2.456)
(parse-long "42")
(parse-long "forty")
(parse-double "2.5")"3 rings"
"rose and sage"
"2.46 metres"
42
nil
2.5Keywords and text #
name gives a keyword's text, and keyword makes a keyword from text:
(name :rain)
(keyword "rain")"rain"
:rainPatterns #
A pattern, #"…", describes text to look for. re-find answers the first piece of text that fits, re-seq every piece, and re-matches the text only when all of it fits:
(re-find #"[0-9]+" "it rang 12 times")
(re-seq #"[a-z]+" "Rose, sage and moss")
(re-matches #"[a-z]+" "bell")
(re-matches #"[a-z]+" "bell 2")"12"
("ose" "sage" "and" "moss")
"bell"
nil[a-z]+ means one or more small letters, so the capital R of "Rose" isn't part of a match. Patterns are useful, but for most words a toy hears, includes? and words are plainer, and chapter 10 has a word, match, made for it.
Lists #
These words read a list. Places are counted from 0:
(first ["rose" "sage" "moss"])
(second ["rose" "sage" "moss"])
(last ["rose" "sage" "moss"])
(nth ["rose" "sage" "moss"] 1)
(nth ["rose" "sage" "moss"] 5 "none")
(count ["rose" "sage" "moss"])
(rest ["rose" "sage" "moss"])
(empty? [])"rose"
"sage"
"moss"
"sage"
"none"
3
("sage" "moss")
truenth with a third value answers that value when the place is past the end. Without one, a place past the end stops the plan (chapter 17).
These answer new lists:
(conj ["rose" "sage"] "moss")
(cons "fern" ["rose" "sage"])
(concat ["rose"] ["sage" "moss"])
(take 2 ["rose" "sage" "moss"])
(drop 2 ["rose" "sage" "moss"])
(take-last 2 ["rose" "sage" "moss"])
(reverse [1 2 3])
(sort [3 1 2])
(distinct [1 1 2 1])
(vec (range 5))["rose" "sage" "moss"]
("fern" "rose" "sage")
("rose" "sage" "moss")
("rose" "sage")
("moss")
("sage" "moss")
(3 2 1)
(1 2 3)
(1 2)
[0 1 2 3 4]Some answers print in round brackets: they are lists all the same, of the kind Lisp makes as it goes. vec turns one into square brackets when you want to keep it. conj adds to the end of a square-bracket list; cons adds to the front.
range counts: (range 5) is 0 to 4, (range 2 5) is 2, 3 and 4, and (range 0 10 3) goes up in threes.
Maps #
A map holds values under keys. These read one:
(get {:rings 4 :colour "rose"} :colour)
(:rings {:rings 4 :colour "rose"})
(get {:rings 4} :chimes 0)
(keys {:rings 4 :colour "rose"})
(vals {:rings 4 :colour "rose"})
(contains? {:rings 4} :rings)
(get-in {:bell {:rings 4}} [:bell :rings])
(count {:rings 4 :colour "rose"})"rose"
4
0
(:rings :colour)
(4 "rose")
true
4
2And these answer new maps:
(assoc {:rings 4} :colour "rose")
(dissoc {:rings 4 :colour "rose"} :colour)
(update {:rings 4} :rings inc)
(merge {:rings 4} {:colour "rose"})
(select-keys {:rings 4 :colour "rose" :open true} [:rings :open])
(assoc-in {} [:bell :rings] 1)
(update-in {:bell {:rings 1}} [:bell :rings] inc)
(zipmap [:rose :sage] [3 5]){:rings 4, :colour "rose"}
{:rings 4}
{:rings 5}
{:rings 4, :colour "rose"}
{:rings 4, :open true}
{:bell {:rings 1}}
{:bell {:rings 2}}
{:rose 3, :sage 5}update takes a key and a word to apply to its value: (update m :rings inc) adds one to :rings. Keys are usually keywords, but text works too: {"@mira" 2 "@cairn" 1} is a map from names to counts, and chapter 12 uses one.
Sets #
A set holds each value once. conj adds, disj takes away, and contains? asks:
(conj #{"rose"} "sage" "rose")
(disj #{"rose" "sage"} "rose")
(contains? #{"rose" "sage"} "sage")
(set ["rose" "sage" "rose"])#{"rose" "sage"}
#{"sage"}
true
#{"rose" "sage"}A set prints its values in an order of its own. Use a set when what matters is whether something is there, and a list when order matters.
One trap: contains? on a list asks about places, not values. (contains? ["rose"] 0) is true because there is a place 0. To ask whether a list holds a value, make it a set first: (contains? (set guests) "@mira").
Try it #
- Answer
"BELL, CHIME, GONG"from the list["bell" "chime" "gong"]. - From
"Mira says the tea is ready", answer how many words it has. - Start with
{:rings 0}and answer a map with:rings1 and:last "@mira". - Answer the last two items of
(range 10)as a square-bracket list. - Answer whether the text
"rain later"mentions rain, and whether it starts with it.
Recap #
- Text:
str,count,subs,upper,lower,trim,includes?,starts-with?,ends-with?,replace-all,words,split,join,format,parse-long. - Lists:
first,rest,nth,count,conj,concat,take,drop,sort,range,vec. - Maps:
get,(:k m),assoc,dissoc,update,merge,keys,vals,get-in,assoc-in. - Sets hold each value once;
contains?asks about keys and places, not list values.
Next: making choices.
Written by Claude, Plazmi's writer, for Plazmi, a service of Manatee Media LLC. Text © 2026 Manatee Media LLC. The examples are free to copy, change and run.