In the last lesson you learned a bit about how to use cores as state machines. In this lesson you'll expand on that knowledge, in particular by learning how to use the `=^`

rune. At the end of the lesson you'll learn how to write a generator that shuffles a 52 card deck and deals hands from it.

`num`

Core Again In the last lesson we used a simple door to illustrate the use of doors as state machines. Let's modify the code for that core slightly:

|_ a/@ ++ this . :: ++ inc [+(a) this(a +(a))] :: ++ plus |= [email protected] [(add a b) this(a (add a b))] :: ++ reset [a this(a 0)] --

The `this`

arm is unchanged. The other arms -- `inc`

, `plus`

, and `reset`

-- no longer evaluate to cores. They evaluate to cells in which the head is some value of type `@`

, and the tail is a core, i.e., a variant of `this`

. The idea behind these changes is that each arm should produce not just a new state, but a relevant atom value for the sample as well. When `inc`

is evaluated the new value for `a`

is produced, along with the new version of the core. When `reset`

is evaluated, the sum total of `a`

is produced, along with the new version of the core in which `a`

is set to `0`

.

Here's a new version of the program that uses this new core code:

|= [email protected] =/ num :: define the `num` core |_ a/@ ++ this . :: ++ inc [+(a) this(a +(a))] :: ++ plus |= [email protected] [(add a b) this(a (add a b))] :: ++ reset [a this(a 0)] -- =^ v1 num inc.num :: increment `a` by 1, store in `v1` =^ v2 num inc.num :: do it again, storing `a` in `v2` =^ v3 num (plus:num c) :: add `c` to `a`, store in `v3` =^ v4 num (plus:num c) :: do it again, storing `a` in `v4` =^ v5 num reset.num :: reset `a` to `0`, total in `v5` [v1 v2 v3 v4 v5] :: return `v1` through `v5`

Save this as `numcore2.hoon`

in `/gen`

of your urbit's pier and run it in the dojo:

> +numcore2 10 [1 2 12 22 22] > +numcore2 100 [1 2 102 202 202] > +numcore2 500 [1 2 502 1.002 1.002]

Now you can see the intermediate values of the sample of `a`

for each modified version of the `num`

core that was created. Of course, you can't really understand how this program works until you understand what the `=^`

rune does.

`=^`

Pin a Value and Replace a Leg The `=^`

rune takes four subexpressions: `=^(a b c d)`

. The first three modify the subject, and the `d`

is evaluated against that subject. `a`

is a face name, `b`

is a wing, and `c`

is an expression that evaluates to a cell. The subject is modified as follows: (1) `c`

is evaluated, producing a cell; (2) the head of that cell is pinned to the subject, `a`

becoming the face name for it; and (3) the wing at `b`

is replaced with the tail of the cell produced by `c`

.

This is particularly useful when you want to return data for the form `[result new-state]`

.

For example, let's consider `=^ v1 num inc.num`

from the program above. `inc.num`

produces a cell, the head of which is an atom. This atom is pinned to the head of the subject and given the face name `v1`

. The tail of the cell produced by `inc.num`

is a variant of the `num`

core, and becomes the new value of `num`

. The fourth subexpression of this `=^`

expression is the rest of the program, i.e.:

=^ v2 num inc.num =^ v3 num (plus:num c) =^ v4 num (plus:num c) =^ v5 num reset.num [v1 v2 v3 v4 v5]

The `=^`

rune was designed for use with state machine data structures, doors in particular. Understanding `=^`

is important! This whole lesson is intended to emphasize the use and importance of this rune.

You'll notice that the `plus`

arm of the `num`

core above evaluates to a gate.

++ plus |= [email protected] [(add a b) this(a (add a b))]

But this gate doesn't have a cast in it, and that's bad practice. Any time you produce a gate you should include a cast. The desired output type of the `plus`

gate is a cell whose head is an atom and whose tail is a core of the same type as `num`

. We know how to cast for the head -- it's just an atom, `@`

. But what about the tail? How do we cast for a core of the same type as `num`

?

There is no straight-forward way of casting for a core in general, and anyway that isn't what is desired in this case. We don't want `plus`

to produce just any core; we want it to produce a core of the same type as `num`

.

One way to cast appropriately is to use the `^+`

rune, as in the following:

++ plus |= [email protected] ^+ [0 this] [(add a b) this(a (add a b))]

The relevant addition is the line with `^+ [0 this]`

. The `^+`

rune is used when one wants to do a cast with an example noun, i.e., when you want to cast for a value of the same type as the example. The example `[0 this]`

is a cell type whose head is an `@ud`

, and whose tail is a core of the same type as `this`

. And `this`

is how the `num`

core refers to itself.

`$_`

Create a Type From an Example Another way to add a cast to the `plus`

arm is to use the `$_`

rune to create a core type. This rune allows us to use the `^-`

cast rune instead, as in the following:

++ plus |= [email protected] ^- [@ $_(this)] [(add a b) this(a (add a b))]

The `$_`

rune takes one subexpression. That subexpression is evaluated, and the type of the resulting noun is the type produced. The default value of that type is exactly the noun used to create it.

The irregular form of `$_( )`

is just `_`

, so we can shorten the cast above to:

++ plus |= [email protected] ^- [@ _this] [(add a b) this(a (add a b))]

This kind of casting is relatively common. It's generally used in cores used as state machines.

`_+>.$`

Construction Another way to cast for the type of the parent core of an arm is to use `_+>.$`

. This construction looks a bit complicated, but it's also used somewhat frequently in the Urbit codebase. It's worth a closer examination. We can use it in the `plus`

arm as follows:

++ plus |= [email protected] ^- [@ _+>.$] [(add a b) this(a (add a b))]

But what does it mean? First, the `_`

indicates the irregular form of the `$_`

rune. That is, `_+>.$`

evaluates `+>.$`

and produces a type from the resulting noun.

What is `+>.$`

? This is a wing of two limbs, `+>`

and `$`

. As you saw in section 1.4, `+>`

is the lark syntax for `+7`

, i.e., address space `7`

. And `$`

is the name of the lone arm in a gate. Whenever an arm name is used in a wing expression and isn't the left-most limb in the series, it evaluates to its parent core. The parent core of `$`

is the gate itself.

Thus, `+>.$`

evaluates to `+7`

of the gate containing `$`

. For our `plus`

arm, the gate in question is the one defined by:

|= [email protected] ^- [@ _+>.$] [(add a b) this(a (add a b))]

What is `+7`

of this gate? It's the subject of the expression used to define the gate. This gate is produced by the `plus`

arm. Every arm in the `num`

core, including `plus`

, is evaluated with the `num`

core as the subject. Hence, `+>.$`

is just the `num`

core.

It follows that `_+>.$`

is the type of the `num`

core.

The `=^`

rune can be used with the `og`

door in the Hoon standard library to generate random numbers. We'll illustrate this.

First, let's use the `rad`

arm in the `og`

core. This arm takes an atom `n`

, and produces another atom somewhere in the range of `0`

to `n - 1`

(inclusive):

> (rad:og 3) 0 > (rad:og 4) 2 > (rad:og 5) 4 > (rad:og 55) 50 > (rad:og 155) 108

Are these numbers randomly generated? Not really. The `og`

core uses a 'seed number' which determines how a number is generated from the functions in `og`

. The seed number is stored in the sample of the `og`

core as an atom. In other words, `og`

is a door whose 'state' is the seed number. The default seed number is `0`

. If we use `rad`

in `og`

without changing the sample of the latter, the number produced by `rad`

is always the same per any given argument. E.g., `(rad:og 55)`

will produce `50`

every time.

To change the seed, we need to make a copy of `og`

with a different sample. How do we do that? We do it as follows:

> ~(. og 123) <4.rvc {a/@ud <51.zox 93.pqh 74.dbd 1.qct $141>}> > ~(. og 456) <4.rvc {a/@ud <51.zox 93.pqh 74.dbd 1.qct $141>}> > ~(. og 456.789) <4.rvc {a/@ud <51.zox 93.pqh 74.dbd 1.qct $141>}>

The seeds of these three cores are `123`

, `456`

, and `456.789`

, respectively. We can use these variants of `og`

with `rad`

to get different values from the ones we got before:

> (rad:~(. og 123) 3) 1 > (rad:~(. og 123) 4) 3 > (rad:~(. og 123) 5) 3 > (rad:~(. og 123) 55) 28 > (rad:~(. og 123) 155) 58

This can be a bit tedious, however. And, in any case, this syntax requires that we pick a seed value manually.

Part of the solution is to use the `rads`

arm of `og`

with the `=^`

rune. The gate defined by the `rads`

arm takes an atom `n`

produces a pair of: (1) another atom somewhere in the range of `0`

to `n - 1`

(inclusive); and (2) another version of the `og`

core with a different seed value.

> (rads:og 3) [0 <4.rvc {a/@ <51.zox 93.pqh 74.dbd 1.qct $141>}>] > (rads:og 4) [2 <4.rvc {a/@ <51.zox 93.pqh 74.dbd 1.qct $141>}>] > (rads:og 5) [4 <4.rvc {a/@ <51.zox 93.pqh 74.dbd 1.qct $141>}>] > (rads:og 55) [50 <4.rvc {a/@ <51.zox 93.pqh 74.dbd 1.qct $141>}>]

Let's create a copy of the `og`

core in the dojo, giving it the face `rng`

. By first putting it in the subject as a door, we're able to mutate it. (Strictly speaking, there is no `og`

door until the `++ og`

arm in the Hoon standard library is evaluated. If you try to mutate it before putting a copy of the core in the subject, you'll run into problems.) Let's make a copy of the `og`

door with its initial seed value as `123`

:

> =rng ~(. og 123) > rng <4.rvc {a/@ud <51.zox 93.pqh 74.dbd 1.qct $141>}> > +6:rng a=123

Good. Now let's use the `=^`

rune with `rng`

. Paste the multi-line expression into the dojo:

> =^ r1 rng (rads:rng 3) =^ r2 rng (rads:rng 4) =^ r3 rng (rads:rng 5) =^ r4 rng (rads:rng 55) =^ r5 rng (rads:rng 155) [r1 r2 r3 r4 r5] [1 0 4 22 88]

For each random number generation, the `rng`

core has a different seed number. However, we still picked the initial seed value. This isn't random enough; given the same initial seed and the same arguments for `rads`

, the resulting numbers produced by `rads`

will be the same as well. This is what `eny`

is for:

> eny \/0v3en.c4udf.jg3op.njvu9.sdhp3.oq9vm.j5g93.2njmu.6bk6j.agjme.ef451.7icfo.134\/ fv.i4dor.dv6ls.9m7ig.vb8m7.ir3mb.gt7vn.q57l6.sant1 \/ \/ > eny \/0v1hu.1i95m.infcn.a6sc2.47fph.idjoc.2jcd4.2hj3p.ma12d.jtphu.5585b.9t0ru.48q\/ 61.3qmpl.gvn5b.evhl3.us653.kffap.vef21.kaavg.p5sl3 \/ \/

`eny`

is an environment value for entropy. Its value changes every time it's evaluated. We can use `eny`

to produce a seed value for `rng`

and retry the `=^`

expression from above:

> =rng ~(. og eny) > =^ r1 rng (rads:rng 3) =^ r2 rng (rads:rng 4) =^ r3 rng (rads:rng 5) =^ r4 rng (rads:rng 55) =^ r5 rng (rads:rng 155) [r1 r2 r3 r4 r5] [0 2 4 51 40]

(Your output values will differ.)

Let's write a gate that shuffles and deals from a deck of cards. We'll start with a simpler gate that produces an unshuffled deck.

|= * =| sorted=(list [@tas @tas]) =/ values=(list @tas) :* %two %three %four %five %six %seven %eight %nine %ten %jack %queen %king %ace ~ == =/ suits=(list @tas) ~[%spades %diamonds %clubs %hearts] |- ^- (list [@tas @tas]) ?~ suits sorted %= $ suits t.suits sorted |- ^- (list [@tas @tas]) ?~ values sorted [[i.values i.suits] $(values t.values)] ==

Save this as `deck.hoon`

in the `/gen`

directory of your urbit's pier and run in the dojo:

> +deck 1 ~[ [%two %hearts] [%three %hearts] [%four %hearts] [%five %hearts] [%six %hearts] [%seven %hearts] [%eight %hearts] [%nine %hearts] [%ten %hearts] [%jack %hearts] [%queen %hearts] [%king %hearts] [%ace %hearts] [%two %clubs] [%three %clubs] [%four %clubs] [%five %clubs] [%six %clubs] [%seven %clubs] [%eight %clubs] [%nine %clubs] [%ten %clubs] [%jack %clubs] [%queen %clubs] [%king %clubs] [%ace %clubs] [%two %diamonds] [%three %diamonds] [%four %diamonds] [%five %diamonds] [%six %diamonds] [%seven %diamonds] [%eight %diamonds] [%nine %diamonds] [%ten %diamonds] [%jack %diamonds] [%queen %diamonds] [%king %diamonds] [%ace %diamonds] [%two %spades] [%three %spades] [%four %spades] [%five %spades] [%six %spades] [%seven %spades] [%eight %spades] [%nine %spades] [%ten %spades] [%jack %spades] [%queen %spades] [%king %spades] [%ace %spades] ]

(This gate doesn't use the sample for anything, but you still have to give one when you run the generator. That's because of the kind of generator this is, 'naked'.)

We can create our own types for use with this generator. In the following modified version, we create the types `value`

for card value, `suit`

for card suit, and `card`

for a pair of value and suit. We put these definitions into a core and put that core into the subject so we can use them from elsewhere in the gate.

|= * =< =| sorted=(list card) =/ values=(list value) :* %two %three %four %five %six %seven %eight %nine %ten %jack %queen %king %ace ~ == =/ suits=(list suit) ~[%spades %diamonds %clubs %hearts] |- ^- (list card) ?~ suits sorted %= $ suits t.suits sorted |- ^- (list card) ?~ values sorted [[i.values i.suits] $(values t.values)] == :: |% :: +$ card [value suit] :: +$ value @tas :: +$ suit $? %clubs %hearts %spades %diamonds == --

This version of the gate produces the same result as the last version, but uses the custom types we defined instead of the native Hoon types.

Next, let's use the `og`

core to shuffle the deck of cards:

|= * =< =/ deck=(list card) sorted-deck :: `deck` is sorted deck of cards =| shuffled=(list card) :: `shuffled` is shuffled deck =/ [email protected] (lent deck) :: `len` is # of cards in `deck` =/ rng ~(. og 123) :: `rng` is copy of `og` core, seed 123 |- ^- (list card) ?: =(~ deck) shuffled :: when `deck` is null, return shuffled =^ val rng (rads:rng len) :: `val` picks random card from `deck` %= $ shuffled [(snag val deck) shuffled] :: add random card to `shuffled` deck (oust [val 1] deck) :: remove that card from `deck` len (dec len) :: decrement # of cards in `deck` == :: |% :: ++ sorted-deck =| sorted=(list card) =/ values=(list value) :* %two %three %four %five %six %seven %eight %nine %ten %jack %queen %king %ace ~ == =/ suits=(list suit) ~[%spades %diamonds %clubs %hearts] |- ^- (list card) ?~ suits sorted %= $ suits t.suits sorted |- ^- (list card) ?~ values sorted [[i.values i.suits] $(values t.values)] == :: +$ card [value suit] :: +$ value @tas :: +$ suit $? %clubs %hearts %spades %diamonds == --

Save this as a new copy of `deck.hoon`

and run it in the dojo:

> +deck 1 ~[ [%two %clubs] [%five %diamonds] [%ace %spades] [%three %hearts] [%queen %clubs] [%four %clubs] [%seven %hearts] [%king %clubs] [%seven %clubs] [%six %diamonds] [%nine %diamonds] [%eight %clubs] [%eight %spades] [%king %hearts] [%four %hearts] [%ten %clubs] [%jack %clubs] [%nine %hearts] [%six %hearts] [%five %clubs] [%nine %spades] [%two %hearts] [%three %clubs] [%queen %hearts] [%five %hearts] [%five %spades] [%six %spades] [%ten %hearts] [%king %diamonds] [%three %spades] [%eight %hearts] [%king %spades] [%ten %diamonds] [%queen %diamonds] [%nine %clubs] [%jack %hearts] [%queen %spades] [%jack %diamonds] [%eight %diamonds] [%jack %spades] [%three %diamonds] [%four %spades] [%ace %hearts] [%ten %spades] [%two %spades] [%ace %diamonds] [%six %clubs] [%seven %spades] [%seven %diamonds] [%two %diamonds] [%ace %clubs] [%four %diamonds] ]

The deck is shuffled, but the way it's shuffled depends upon the seed value manually entered for `rng`

. You can use `eny`

in the dojo, but this environment value isn't available in the kind of generator we're using above. We've been using 'naked' generators in this chapter. Let's use a different kind which does have access to `eny`

: a `%say`

generator.

A naked generator must evaluate to a gate, but a `%say`

generator must evaluate to a pair of (1) the `@tas`

noun `%say`

, and (2) a gate. But the latter can't be just any gate. The gate in (2) must produce a pair of (1) type information, and (2) output of the type indicated in (1).

We won't explain all the details of `%say`

generators here; that's for a later tutorial. But we'll show a version of the program above that can use `eny`

as entropy for the `rng`

seed:

:- %say :: pair of `%say` and gate |= [[* [email protected] *] [* ~] ~] :: don't worry about this line for now :- %noun :: pair of `%noun` and gate output =< =/ deck=(list card) sorted-deck =| shuffled=(list card) =/ [email protected] (lent deck) =/ rng ~(. og eny) :: `rng` has seed of `eny` |- ^- (list card) ?: =(~ deck) shuffled =^ val rng (rads:rng len) %= $ shuffled [(snag val deck) shuffled] deck (oust [val 1] deck) len (dec len) == :: |% :: ++ sorted-deck =| sorted=(list card) =/ values=(list value) :* %two %three %four %five %six %seven %eight %nine %ten %jack %queen %king %ace ~ == =/ suits=(list suit) ~[%spades %diamonds %clubs %hearts] |- ^- (list card) ?~ suits sorted %= $ suits t.suits sorted |- ^- (list card) ?~ values sorted [[i.values i.suits] $(values t.values)] == :: +$ card [value suit] :: +$ value @tas :: +$ suit $? %clubs %hearts %spades %diamonds == --

With this version of the program, you get a different sorted deck of cards each time it's run!

Let's use a door as a state machine. The state will have two parts: (1) `deck`

, a deck of cards, and (2) `rng`

, a copy of the `og`

core with a seed value. Instead of having functions that produce a sorted deck of cards or a shuffled deck of cards, let's have the arms of this door compute a new version of the state machine with an appropriately modified state.

We'll use this state machine in a program that deals `a`

hands of `b`

cards each:

:: :: carddeal.hoon :: :: this program deals cards from a randomly shuffled deck. :: :: save as `carddeal.hoon` in the `/gen` directory of your :: urbit's pier and run in the dojo: :: :: +carddeal [4 5] :: :: :: this is a %say generator; unlike naked gens, these have access :: to environment data such as entropy :: :- %say :: :: a is the number of hands to be dealt :: b is the number of cards per hand :: |= [[* [email protected] *] [[[email protected] [email protected]] ~] ~] :- %noun =< :: :: `cards` is a core with a shuffled deck and `rng` as state :: =/ cards shuffle:sorted-deck:cards |- ^- (list (list card)) ?: =(0 a) ~ :: :: `draw` returns a pair of [hand cards] :: `hand` is a list of cards, i.e. a dealt hand, and :: `cards` is the core with a modified deck :: (the cards of `hand` were removed from the deck) :: =^ hand cards (draw:cards b) [hand $(a (dec a))] :: |% :: :: a `card` is a pair of [value suit] :: +$ card [value suit] :: :: a `value` is a `@tas`, e.g., %two, %queen :: +$ value @tas :: :: the card suits are: clubs, hearts, spades, :: and diamonds :: +$ suit $? %clubs %hearts %spades %diamonds == :: :: `cards` is a door with `deck` and `rng` as state :: `deck` is a deck of cards :: `rng` is a Hoon stdlib core for random # generation :: a door is a core with a sample, often multi-arm :: ++ cards |_ [deck=(list card) rng=_~(. og eny)] :: :: `this` is, by convention, how a door refers :: to itself :: ++ this . :: :: `draw` returns two things: (1) a list of cards (i.e. a hand), :: and (2) a modified core for `cards`. the `deck` in `cards` :: has the dealt cards removed. :: ++ draw |= [email protected] =| hand=(list card) |- ^- [(list card) _this] ?: =(0 a) [hand this] ?~ deck !! %= $ hand [i.deck hand] deck t.deck a (dec a) == :: :: `shuffle` returns the `cards` core with a modifed `deck`. :: the cards in the deck have been shuffled randomly. :: ++ shuffle =| shuffled=(list card) =/ [email protected] (lent deck) |- ^- _this ?: =(~ deck) this(deck shuffled) =^ val rng (rads:rng len) %= $ shuffled [(snag val deck) shuffled] deck (oust [val 1] deck) len (dec len) == :: :: `sorted-deck` returns the `cards` core with a modifed :: `deck`. the full deck of cards is provided, unshuffled. :: ++ sorted-deck %_ this deck =| sorted=(list card) =/ values=(list value) :* %two %three %four %five %six %seven %eight %nine %ten %jack %queen %king %ace ~ == =/ suits=(list suit) ~[%spades %diamonds %clubs %hearts] |- ^- (list card) ?~ suits sorted %= $ suits t.suits sorted |- ^- (list card) ?~ values sorted [[i.values i.suits] $(values t.values)] == == -- --

Save this as `carddeal.hoon`

in `/gen`

of your urbit's pier and run in the dojo:

> +carddeal [3 4] ~[ ~[[%queen %spades] [%jack %hearts] [%three %diamonds] [%six %spades]] ~[[%king %diamonds] [%eight %hearts] [%five %clubs] [%two %diamonds]] ~[[%three %clubs] [%nine %spades] [%six %diamonds] [%three %hearts]] ] > +carddeal [3 4] ~[ ~[[%king %clubs] [%ten %clubs] [%ten %diamonds] [%seven %spades]] ~[[%six %hearts] [%six %clubs] [%three %spades] [%four %hearts]] ~[[%seven %clubs] [%jack %diamonds] [%two %spades] [%five %spades]] ] > +carddeal [3 4] ~[ ~[[%seven %diamonds] [%nine %clubs] [%five %diamonds] [%three %diamonds]] ~[[%ace %spades] [%jack %spades] [%two %spades] [%nine %hearts]] ~[[%king %diamonds] [%six %spades] [%queen %clubs] [%eight %clubs]] ]

You get a different set of hands each time you run the generator.