# Answers to the exercises

From A Little Lisp for a Small World, the Plazmi Lisp book (https://plazmi.gg/book). Checked against Plazmi Lisp version 2, 12 November 2026. The whole book as one file: https://plazmi.gg/book.md

One way to answer each exercise. Most exercises have many good answers; where an answer is code, it was run like every other example in the book, and what it gave is shown.

## Forms and values

1. A week's hours:

```clojure
(* 24 7)
```

```text
168
```

2. Sums inside text:

```clojure
(str (+ 1 2) " bells, " (+ 1 1) " chimes")
```

```text
"3 bells, 2 chimes"
```

3. `str` always answers text, so `(type (str 1 2))` is `:text`:

```clojure
(type (str 1 2))
```

```text
:text
```

4. A map for a bell:

```clojure
{:name "Bell" :rings 4}
```

```text
{:name "Bell", :rings 4}
```

## Names

1. A room's area:

```clojure
(let [width 4
      depth 3]
  (* width depth))
```

```text
12
```

2. `name` is a word of the language, so don't take it apart into a name of that name: take `:rings` apart, and read `:name` with its keyword.

```clojure
(let [bell {:name "Bell" :rings 7}
      {:keys [rings]} bell]
  (str (:name bell) ": " rings))
```

```text
"Bell: 7"
```

3. `count` is a word of the language. Even where Plazmi renames it for you and the plan runs, a reader sees `count` and thinks of the word. Call it `stools`, or whatever it counts.

4. Adding up 0 to 9 with an atom:

```clojure
(let [total (atom 0)]
  (dotimes [i 10]
    (swap! total + i))
  (deref total))
```

```text
45
```

## Text, lists and maps

1. Capitals, joined:

```clojure
(join ", " (map upper ["bell" "chime" "gong"]))
```

```text
"BELL, CHIME, GONG"
```

2. Counting words:

```clojure
(count (words "Mira says the tea is ready"))
```

```text
6
```

3. Two keys set at once (`assoc` takes as many pairs as you give it):

```clojure
(assoc {:rings 0} :rings 1 :last "@mira")
```

```text
{:rings 1, :last "@mira"}
```

4. The last two, kept as a list:

```clojure
(vec (take-last 2 (range 10)))
```

```text
[8 9]
```

5. Mentions, and starts with:

```clojure
(includes? "rain later" "rain")
(starts-with? "rain later" "rain")
```

```text
true
true
```

## Tests and choices

1. Three ways, narrowest first:

```clojure
(let [temperature 15]
  (cond (< temperature 10) "cold"
        (< temperature 20) "mild"
        :else "warm"))
```

```text
"mild"
```

2. A greeting for each time of day:

```clojure
(case :dusk
  :dawn "Up early."
  :day "Good day."
  :dusk "Good evening."
  :night "Good night.")
```

```text
"Good evening."
```

3. `or` answers the first value that counts as true, or the last if none does; `and` answers the last if all do:

```clojure
(or nil false)
(and 1 2 3)
```

```text
false
3
```

4. The first even number, doubled:

```clojure
(if-let [n (first (filter even? [1 3 4 5]))]
  (* 2 n)
  "none")
```

```text
8
```

## Working over lists

1. Squares, kept:

```clojure
(mapv (fn [n] (* n n)) (range 1 11))
```

```text
[1 4 9 16 25 36 49 64 81 100]
```

2. Who came most: count each, then take the key with the biggest count:

```clojure
(key (apply max-key val (frequencies ["@mira" "@cairn" "@mira" "@wisp" "@mira"])))
```

```text
"@mira"
```

3. The longest word, by folding:

```clojure
(reduce (fn [longest w] (if (> (count w) (count longest)) w longest))
        ""
        ["oak" "willow" "fern"])
```

```text
"willow"
```

4. Names starting `@m`:

```clojure
(filter #(starts-with? % "@m") ["@mira" "@cairn" "@moss"])
```

```text
("@mira" "@moss")
```

## Functions

1. A function that shouts:

```clojure
(defn shout [t] (str (upper t) "!"))
(shout "ting")
```

```text
"TING!"
```

2. Plus 100:

```clojure
(map #(+ % 100) [1 2 3])
```

```text
(101 102 103)
```

3. Adding up a list by calling itself, and with `reduce`:

```clojure
(defn sum-list [l]
  (if (empty? l) 0 (+ (first l) (sum-list (rest l)))))
(sum-list [1 2 3 4])
(reduce + 0 [1 2 3 4])
```

```text
10
10
```

4. The first power of 2 over 1,000:

```clojure
(loop [n 1]
  (if (> n 1000) n (recur (* n 2))))
```

```text
1024
```

## Chance that repeats

1. Three dice; the total is chance, from 3 to 18:

```clojure
(+ (inc (rand-int 6)) (inc (rand-int 6)) (inc (rand-int 6)))
```

```text
…
```

2. A week, shuffled:

```clojure
(shuffle ["Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"])
```

```text
[…]
```

3. Each run's seed is made from who runs it as well as the world's place in its history, so two residents at the same moment start from different seeds.

4. A coin:

```clojure
(defobject coin
  {:name "Coin"
   :verbs {:flip (fn [self who] (say self (rand-nth ["Heads." "Tails."])))}})
```

```text
> flip coin
[Juniper's coin] …
```

## Reading your own home

1. Spending 35 of 50:

```clojure
(if (>= (coins) 35) (- (coins) 35) "not enough")
```

```text
15
```

2. The rooms, as one text:

```clojure
(join ", " (map :id (:rooms (house))))
```

```text
"kitchen, living, bath, bedroom"
```

3. By the time of day:

```clojure
(if (= :night (:time (sky))) "Bonsoir." "Bonjour.")
```

```text
"Bonsoir."
```

4. Hours until dusk, at 18:00, from the hour in `"HH:MM"`. (In the book's world it is just after one in the morning.)

```clojure
(let [hour (parse-long (first (split (:time (world-time)) ":")))]
  (- 18 hour))
```

```text
17
```

## A first toy

1. A kettle:

```clojure
(defobject kettle
  {:name "Kettle"
   :state {:cups 0}
   :verbs {:pour (fn [self who]
                   (put! self :cups (inc (:cups self)))
                   (say self (str "A cup poured. That's " (:cups self) " today.")))}})
```

```text
> pour kettle
[Juniper's kettle] A cup poured. That's 1 today.
```

2. A bell that can be hushed:

```clojure
(defobject bell
  {:name "Bell"
   :state {:rings 0}
   :verbs {:ring (fn [self who]
                   (put! self :rings (inc (:rings self)))
                   (say self (str "Ting. " (:rings self) " so far.")))
           :hush (fn [self who]
                   (put! self :rings 0)
                   (say self "The bell is still. Back to none."))}})
```

```text
> ring bell
[Juniper's bell] Ting. 1 so far.
> hush bell
[Juniper's bell] The bell is still. Back to none.
> ring bell
[Juniper's bell] Ting. 1 so far.
```

3. A first play, and every one after:

```clojure
(defobject music-box
  {:name "Music box"
   :state {:plays 0}
   :verbs {:wind (fn [self who]
                   (put! self :plays (inc (:plays self)))
                   (say self (if (= 1 (:plays self))
                               "A tune you've never heard before."
                               "The same tune, a little slower.")))}})
```

```text
> wind music box
[Juniper's music box] A tune you've never heard before.
> wind music box
[Juniper's music box] The same tune, a little slower.
```

4. A verb that says nothing still runs; the visitor is told they played it, and the toy says nothing:

```clojure
(defobject pebble
  {:name "Pebble"
   :verbs {:turn (fn [self who] nil)}})
```

```text
> turn pebble
```

## A toy that listens

1. An owl that hears "night" only as a whole word:

```clojure
(defobject owl
  {:name "Owl"
   :on-hear (fn [self who text]
              (when (some #{"night"} (words (lower text)))
                (say self "Hoo.")))})
```

```text
> say what a night
[Juniper's owl] Hoo.
> say a nightingale sang
```

2. A riddle chosen by a count: keep `:riddle 0` in the state, a list of riddles and answers, and read the one at `(mod riddle (count riddles))`; when it's answered, add one to `:riddle`.

3. "Bless you." only for words said to nobody:

```clojure
(defobject tabby
  {:name "Tabby"
   :on-hear (fn [self who text]
              (when (and (nil? (:to self)) (not (:spoken-to self)) (includes? (lower text) "achoo"))
                (say self "Bless you.")))})
```

```text
> say achoo
[Juniper's tabby] Bless you.
```

4. A mirror for its maker alone: test `(= who "@you")` as well as `(:spoken-to self)`.

## Keeping time

1. A calendar of dawns:

```clojure
(defobject calendar
  {:name "Calendar"
   :state {:day 0}
   :verbs {:read (fn [self who] (say self (str "Day " (:day self))))}
   :on-tick (fn [self] (put! self :day (inc (:day self))))})
```

```text
> read calendar
[Juniper's calendar] Day 0
```

2. By the time of day, in a toy:

```clojure
(defobject door-plate
  {:name "Door plate"
   :verbs {:read (fn [self who]
                   (say self (if (= :night (:time (sky))) "Bonsoir." "Bonjour.")))}})
```

```text
> read door plate
[Juniper's door plate] Bonsoir.
```

3. A weather vane:

```clojure
(defobject vane
  {:name "Weather vane"
   :verbs {:spin (fn [self who] (say self (str "The wind is " (name (:wind (weather))) ".")))}})
```

```text
> spin weather vane
[Juniper's weather vane] The wind is ….
```

4. A glow of mint:

```clojure
(defobject mint-stone
  {:name "Mint stone"
   :verbs {:rub (fn [self who]
                  (if (glow-colour "mint")
                    (say self "A cool green glow.")
                    (say self "Nothing happens this hour.")))}})
```

```text
> rub mint stone
[Juniper's mint stone] A cool green glow.
```

## A toy with a memory

1. Ten names, never the same twice running:

```clojure
(defobject guest-log
  {:name "Guest log"
   :state {:guests []}
   :verbs {:sign (fn [self who]
                   (let [guests (or (:guests self) [])]
                     (when (not= who (last guests))
                       (put! self :guests (vec (take-last 10 (conj guests who)))))
                     (say self (str "Signed by " (join ", " (:guests self)) "."))))}})
```

```text
> sign guest log
[Juniper's guest log] Signed by Mira.
> sign guest log
[Juniper's guest log] Signed by Mira.
```

2. Votes for each visitor, and who voted most:

```clojure
(defobject ballot-box
  {:name "Ballot box"
   :state {:votes {}}
   :verbs {:vote (fn [self who]
                   (put! self :votes (update (:votes self) who (fnil inc 0)))
                   (say self "Your vote is in."))
           :results (fn [self who]
                      (if (empty? (:votes self))
                        (say self "No votes yet.")
                        (let [[top n] (apply max-key val (:votes self))]
                          (say self (str top " has voted most: " n ".")))))}})
```

```text
> vote ballot box
[Juniper's ballot box] Your vote is in.
> results ballot box
[Juniper's ballot box] Mira has voted most: 1.
```

3. The last word each visitor said, keyed by `who`: `(put! self :last (assoc (:last self) who (last (words text))))` in an `:on-hear`.

4. Made again with `:state {:guests [] :opened 0}`, the guest log keeps the state it had: `:opened` isn't there, and code that reads it should say `(or (:opened self) 0)`. Chapter 18 shows it.

## A small game

1. A bigger game: a second verb `start-big` that puts 21 in the player's game, the same as `start` with another number. Since 21 leaves a remainder of 1 when divided by 4, the pile can win it from the first move.

2. Games played in all: a key `:played` in the state, read with `(or (:played self) 0)`, and one added in `over`.

3. A coin-guessing game:

```clojure
(defobject guessing-coin
  {:name "Guessing coin"
   :state {:tossed {}}
   :verbs {:toss (fn [self who]
                   (put! self :tossed (assoc (:tossed self) who (rand-nth ["heads" "tails"])))
                   (say self "It's in the air. Say heads or tails to the guessing coin."))}
   :on-hear (fn [self who text]
              (when (:spoken-to self)
                (if-let [side (get (:tossed self) who)]
                  (let [guess (first (filter #{"heads" "tails"} (words (lower text))))]
                    (when guess
                      (put! self :tossed (dissoc (:tossed self) who))
                      (say self (if (= guess side) (str "It's " side ". Well guessed.") (str "It's " side ". Not this time.")))))
                  (say self "Toss me first: toss guessing coin."))))})
```

```text
> toss guessing coin
[Juniper's guessing coin] It's in the air. Say heads or tails to the guessing coin.
> say to the guessing coin: heads
[Juniper's guessing coin] It's …. …
```

4. Winners best first: `(sort-by (fn [[k v]] (- v)) (:wins self))`, then the same `join` as before.

## Pictures and dances

1. A plus sign:

```clojure
(design "plus" 7 7
        {:g "#3f8f5a"}
        ["...g..."
         "...g..."
         "...g..."
         "ggggggg"
         "...g..."
         "...g..."
         "...g..."])
```

2. Stripes from a function:

```clojure
(defn stripe [y width] (join "" (repeat width (if (even? y) "r" "w"))))
(apply design (check "stripes" :draw_design
                     {:name "stripes"
                      :palette {:r "#c8553d" :w "#f6ecd6"}
                      :rows (mapv (fn [y] (stripe y 9)) (range 5))}))
```

3. A rainy-day dance:

```clojure
(defdance :rainy-day
  [[:sway {:how :sleepily}] :tiptoe :look [:pause {:how :dreamily}] :hop :hop [:twirl {:how :slowly}] :bow]
  "Rainy day")
```

4. The porch step backwards, from a plan sent after the porch step was made:

```clojure
(defdance :porch-step [:sway :hop :twirl :bow] "Porch step")
```

```clojure
(apply defdance (check "backwards" :make_dance
                       {:name "step-back" :moves (vec (reverse (own :dance "porch-step")))}))
```

## The house as a form

1. Five degrees steeper:

```clojure
(let [pitch (:pitch (-> (house) :masses first :roof))]
  (apply roof (check "steeper" :roof {:pitch (+ pitch 5)})))
```

2. Every side:

```clojure
(window-box :all ["lavender" "butter yellow"])
```

3. A door of chance:

```clojure
(apply paint (check "the door" :paint {:what "door" :shade (rand-nth ["moss" "rose" "slate blue"])}))
```

4. A third part:

```clojure
(house "Juniper's"
       {:part :mass :id "main" :at [3 3] :size [7 6] :stories 1}
       {:part :mass :id "wing" :at [10 4] :size [3 4] :stories 1}
       {:part :mass :id "nook" :at [1 5] :size [2 3] :stories 1})
(map :id (:masses (house)))
```

## Living with others

1. Make it again with `:open true`, and say so to the neighbour; with a key they read it with `source <toy> of <you>`.
2. With a key, `source <toy> of <name>`; through a chat app, go to theirs and `check` with what `toy_lisp`.
3. `:after {:by "<their handle>" :toy "<their toy>"}` in your toy's map, with a key. They hear of it.
4. The refusal names `paint`, and lists what a toy's code can use: its state, its words, its maker's colours, the weather and the language's helpers.

## Limits, errors and refusals

1. `nth` with a value for past the end:

```clojure
(nth [] 0 "none")
```

```text
"none"
```

2. A `cond` on a missing count stops at `(> (:count m) 3)`; `(> (or (:count m) 0) 3)` doesn't:

```clojure
(let [m {}]
  (cond (> (or (:count m) 0) 3) "many"
        :else "few"))
```

```text
"few"
```

3. Divide only when there's something to divide by: `(if (zero? n) "Not yet." (str (/ total n)))`.

4. `(vec (range 200000))` makes 200,000 items at a step each, so it runs out of fuel:

```clojure
(vec (range 200000))
```

```text
Out of fuel: the script stopped at 100000 steps. Nothing was changed.
```

## Style

These are for you to try on your own toys; there's no one answer. A good test of each is to read the toy aloud, as a neighbour would.


---

Before: [Index of examples](https://plazmi.gg/book/example-index.md). Contents: https://plazmi.gg/book.md
