# A toy that listens

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

A verb waits to be played. A toy that listens hears what's said near it, and can answer. This chapter makes a parrot, a riddle stone and a mirror, and shows how to be good company: a toy that answers everything soon wears thin.

## :on-hear

A toy with `:on-hear` hears every line said at your home, by you, a neighbour or a visitor. It is a function of three values: the toy, who spoke, and what they said:

```clojure
(defobject parrot
  {:name "Parrot"
   :on-hear (fn [self who text]
              (when (includes? (lower text) "cracker")
                (say self "Cracker! Cracker!")))})
```

```text
The parrot is ready.
```

```text
> say would you like a cracker
[Juniper's parrot] Cracker! Cracker!
> say lovely weather
```

The parrot heard both lines and answered one. `lower` makes the text small letters first, so "Cracker" and "CRACKER" are heard too.

## Spoken to, or overheard

Words can be said to a toy (`say hello to the parrot`, or `say to the parrot: hello`) or near it, to nobody in particular. A toy can tell: `(:spoken-to self)` is `true` when the words were said to it. And when they were said to someone or something else, `(:to self)` says whom.

A toy that answers only when it's spoken to stays out of other people's conversations:

```clojure
(defobject riddle-stone
  {:name "Riddle stone"
   :state {:answer "echo"}
   :verbs {:tap (fn [self who]
                  (say self "I answer every call and never speak first. What am I?"))}
   :on-hear (fn [self who text]
              (when (:spoken-to self)
                (if (includes? (lower text) (:answer self))
                  (say self "An echo. That's the one.")
                  (say self "Not that one. Think of a valley."))))})
```

```text
The riddle stone is ready.
```

```text
> tap riddle stone
[Juniper's riddle stone] I answer every call and never speak first. What am I?
(To answer: answer <your words>, or say <your words> to the riddle stone.)
> answer a bird
[Juniper's riddle stone] Not that one. Think of a valley.
> say an echo, surely
> say to the riddle stone: an echo
[Juniper's riddle stone] An echo. That's the one.
```

Three things to notice. A verb's line that asks a question, from a toy that listens, is followed by a line saying how to answer. `answer` speaks to the thing that last asked. And "an echo, surely", said to nobody, was overheard and left alone.

## Matching words

`includes?` finds a piece of text anywhere, which is sometimes too much: "bell" is in "bellow". Three other ways to look:

- `(words (lower text))` gives the words, to check with `some` or a set: `((set (words (lower text))) "bell")`.
- `(match text "i love *")` fits text to a pattern of words, where each `*` stands for one or more words. It answers the words the stars took, or `nil` when the text doesn't fit. Case and punctuation don't matter.
- A pattern, `#"…"`, with `re-find`, for anything else.

`match` makes a parrot that listens for a whole phrase:

```clojure
(defobject parrot
  {:name "Parrot"
   :on-hear (fn [self who text]
              (when-let [m (match text "i love *")]
                (say self (str "You love " (first m) "! You love " (first m) "!"))))})
```

```text
The parrot is ready.
```

```text
> say I love the roses
[Juniper's parrot] You love the roses! You love the roses!
> say I'd love some tea
```

"I'd love some tea" doesn't fit "i love *", so the parrot keeps quiet.

## Turning words round

`reflect` turns a line round, as a mirror would: I and you, my and your change places, and the verbs follow:

```clojure
(defobject mirror
  {:name "Mirror"
   :on-hear (fn [self who text]
              (when (:spoken-to self)
                (say self (str (reflect text) "?"))))})
```

```text
The mirror is ready.
```

```text
> say to the mirror: I think you are lovely
[Juniper's mirror] You think I am lovely?
> say to the mirror: my garden needs rain
[Juniper's mirror] your garden needs rain?
```

`reflect` keeps capitals where they were: "I" came back "You" at the start of a sentence, and "my", written small, came back "your".

## Knowing who spoke

`who` is who spoke, as for a verb: `"@mira"` for a neighbour, `"@you"` for the toy's maker. A toy can greet its maker differently:

```clojure
(defobject doormat
  {:name "Doormat"
   :on-hear (fn [self who text]
              (when (:spoken-to self)
                (say self (if (= who "@you")
                            "Welcome home."
                            (str "Wipe your feet, " who ".")))))})
```

```text
The doormat is ready.
```

```text
> say hello to the doormat
[Juniper's doormat] Wipe your feet, Mira.
```

```text
> say hello to the doormat
[Your doormat] Welcome home.
```

## Good company

Words reach every listening toy at your home, so a toy that answers everything answers over every conversation. A few habits keep a listener pleasant:

- Answer when spoken to (`(:spoken-to self)`), or to one word or phrase you chose.
- Leave words said to someone else alone: `(when (nil? (:to self)) …)` answers only words said to nobody in particular, or to it.
- Say one short line, not three.

## Try it

1. Make an owl that says "Hoo." when it hears the word "night", and only as a whole word.
2. Give the riddle stone a second riddle, chosen by a count in its state.
3. Make a toy that answers "Bless you." to "achoo", but only when nobody was spoken to.
4. Make a mirror that answers only its maker.

## Recap

- `:on-hear (fn [self who text] …)` hears every line said at home.
- `(:spoken-to self)` is true when the words were said to the toy; `(:to self)` names whom they were said to otherwise.
- `includes?`, `words`, `match` and `reflect` are made for words heard.
- `who` is `"@you"` for the maker. A good listener answers when spoken to.

Next: a toy that keeps time.


---

Before: [A first toy](https://plazmi.gg/book/first-toy.md). Next: [Keeping time](https://plazmi.gg/book/dawn.md). Contents: https://plazmi.gg/book.md
