Let's create a state machine in Hoon that models the functionality of a traffic
light. Save the code below as
traffic.hoon in your
:- %say |= * :- %noun =+ |% ++ state ?(%red %yellow %green) -- =/ current-state=state %red =+ ^= traffic-light |% ++ look current-state ++ set |= s=state +>.$(current-state s) -- =+ a=traffic-light =+ b=traffic-light =. a (set.a %yellow) [current-state.a current-state.b]
Let's look at the code piece-by-piece.
:- %say |= * :- %noun
Here's the boilerplate code to designate our generator as being a
%say generator. We're using this variant because
it allows us to run the generator without any arguments. It's otherwise not
relevant to the functionality of our program.
=+ |% ++ state ?(%red %yellow %green) --
=+ adds a noun to the subject. In our case, the noun in question is the core
that is opened with
|% and closed with
--. This core is used to store types,
and does that with the arm that it contains.
++ state creates an arm called
state, which will be used as the name of the
new type that is created in the code that follows,
?(%red %yellow %green).
That following code creates a new type from the union of its elements. In this
case, the state can be one of three values:
corresponding to the three colors of a standard traffic light.
Having new types in a separate core is a common idiom in Hoon programs that allows the compiler to do constant folding, which improves performance.
=/ current-state=state %red
The line above creates a noun of type
state - the type that we created with
the arm in previous code chunk - and gives it a default value. Because we are
putting this noun into the subject, it will be available for use in the
traffic-light core we are about to create.
=+ ^= traffic-light |% ++ look current-state ++ set |= s=state +>.$(current-state s) --
=+ ^= traffic-light does two things. The
^= rune assigns a face to that
noun so it's easier to reference. The
=+ rune adds a noun to the subject, in
this case the core that we just assigned a name and start to build on the next
line and assigned the name.
|%, we are finally at the meat of the program. This core that we just
named has two arms:
look, which gives us the current state, defined later; and
set, which gives us a simple way to modify the value of
The gate we are producing with
|= may look a bit strange, so let's break it
s=state allows for an argument of type
state and gives it a face
We first produce a core with one arm named
$ arm will produce a new
current-state changed to match the
s provided when it was called.
How does this work?
. is wing syntax that
applies the wing expression on the left of it to the noun to the right of it.
$ is the arm of the core. Then by using the wing expression
+>, which means
"return the tail of the tail", we traverse the subject to the core to latch onto
its parent core. where we defined the arms
( ) then
lists changes to the core we would like to make as we produce a new one. You
will often see
+>.$ used in this way.
=+ a=traffic-light =+ b=traffic-light
Now we have the last parts of our program. Remember that
=+ allows us to add a
noun to the head of the subject. In this case, we are adding two nouns, one with
a and a second with the face
b. These two nouns will be copies of
traffic-light core, with all the bits we previously created.
=. a (set.a %yellow)
=. changes a leg in the subject. We use the
set arm on
a to produce a gate
and give that the argument of
%yellow. Remember that we are actually producing
a new core in the gate, so we have to then assign that back to the face
Here we simply are creating a new cell that has the
its head and the
b as its tail.
Let's run it in the Dojo to get our product:
> +traffic [%yellow %red]
Modify the generator to include a way to cycle the light without explicitly having to select the next color. That is, if the light is currently
%greenthen the next color would be
%yellowthen the next color should be
Using what you have learned about creating state machines in Hoon, produce a state machine that can act as a vending-machine emulator. It should keep track of the amount of items it has, as well as the amount of money that an item costs. To keep it simple, assume this vending machine only has one item for sale.
Modify your vending machine from exercise 2 to support holding multiple items with different prices.