@@ -7,7 +7,7 @@ next: true
9Now we know enough to write two quick examples: the Sieve of
9Now we know enough to write two quick examples: the Sieve of
10−Eratosthenes (a naive prime sieve) and a tictactoe engine.
10+Eratosthenes (a naive prime sieve) and a tic-tac-toe engine.
12(Note that these are not examples of perfect Hoon code; they are
12(Note that these are not examples of perfect Hoon code; they are
13meant for teaching. They err, more than usual for Hoon, on the
13meant for teaching. They err, more than usual for Hoon, on the
@@ -48,6 +48,12 @@ than its argument, an atom:
49## `sieve`: explanation
49## `sieve`: explanation
53+:cast (list atom) :: 2
54+:var field/(set atom) (silt (gulf 2 thru)) :: 3
51Line `1`: we are building a gate (function) whose sample
57Line `1`: we are building a gate (function) whose sample
52(argument) is `thru`, an atom.
58(argument) is `thru`, an atom.
@@ -65,6 +71,12 @@ product of `main`. (`abet:main` means `:rap(abet main)`.)
65The core is a state machine; `main` produces the core itself,
71The core is a state machine; `main` produces the core itself,
66with the computation completed. `abet` then extracts the result.
72with the computation completed. `abet` then extracts the result.
77+ (sort (~(tap in field) ~) lth) :: 7
68Line `5`: we wrap a core around our existing subject. The
80Line `5`: we wrap a core around our existing subject. The
69`field` and `thru` atoms are within the payload and of course
81`field` and `thru` atoms are within the payload and of course
70remain accessible.
82remain accessible.
@@ -75,6 +87,12 @@ produces a gate that exports the set as a list, prepending it to
75a tail which is nil in this case (and most cases). We sort this
87a tail which is nil in this case (and most cases). We sort this
76list in ascending order with `lth` (less-than).
88list in ascending order with `lth` (less-than).
92+ :var factor/atom 2 :: 10
93+ :loop :like ..main :: 11
78Line `9`: the `main` arm, which performs the main calculation.
96Line `9`: the `main` arm, which performs the main calculation.
80Line `10`: we declare a counter, `factor`, which will iterate
98Line `10`: we declare a counter, `factor`, which will iterate
@@ -83,12 +101,24 @@ up through the factors we're removing.
83Line `11`: we start a loop. The product of the loop is cast to
101Line `11`: we start a loop. The product of the loop is cast to
84`..main`, which is the core we're in (`+1.main`).
102`..main`, which is the core we're in (`+1.main`).
105+ :if (gth (mul factor factor) thru) :: 12
107+ :moar(factor +(factor), ..main (reap factor)) :: 14
86Lines `12` and `13`: we terminate the loop, returning `..main`,
110Lines `12` and `13`: we terminate the loop, returning `..main`,
87if the square of the counter exceeds the range.
111if the square of the counter exceeds the range.
89Line `14`: repeats the loop, incrementing the counter, and
113Line `14`: repeats the loop, incrementing the counter, and
90replacing the core with a version sieved by `reap`.
114replacing the core with a version sieved by `reap`.
118+ :gate factor/atom :: 17
119+ :var count/atom (mul 2 factor) :: 18
92Lines `16` and `17`: the `reap` arm, which produces a gate that
122Lines `16` and `17`: the `reap` arm, which produces a gate that
93removes multiples of a factor from the field (set of possible
123removes multiples of a factor from the field (set of possible
94primes). The sample of this gate is the factor to remove.
124primes). The sample of this gate is the factor to remove.
@@ -96,6 +126,17 @@ primes). The sample of this gate is the factor to remove.
96Line `18`: we declare a variable `count`, an atom, with the
126Line `18`: we declare a variable `count`, an atom, with the
97initial value `(mul 2 factor)`.
127initial value `(mul 2 factor)`.
130+ :loop :like ..reap :: 19
131+ :if (gth count thru) :: 20
134+ count (add count factor) :: 23
135+ field (~(del in field) count) :: 24
99Line `19`: we enter a loop. This loop produces the core itself.
140Line `19`: we enter a loop. This loop produces the core itself.
101Lines `20` and `21`: we are done if the counter is out of range.
142Lines `20` and `21`: we are done if the counter is out of range.
@@ -132,11 +173,11 @@ concise "kernel" style).
135−### `toe`: tictactoe engine
176+### `toe`: tic-tac-toe engine
137−The `toe` tictactoe engine applies a list of events to a game
178+The `toe` tic-tac-toe engine applies a list of events to a game
138−state, producing a list of game actions. Events are tictactoe
179+state, producing a list of game actions. Events are tic-tac-toe
139−moves (`move)`; actions are tictactoe results (`fact`).
180+moves (`move)`; actions are tic-tac-toe results (`fact`).
142:rap :gate feed/(list move) :: 1
183:rap :gate feed/(list move) :: 1
@@ -205,19 +246,32 @@ moves (`move)`; actions are tictactoe results (`fact`).
206### `toe`: explanation
247### `toe`: explanation
250+:rap :gate feed/(list move) :: 1
252+ :loop :cast (list fact) :: 3
208Line `1` wraps a conclusion around a stack of cores. The cores
256Line `1` wraps a conclusion around a stack of cores. The cores
209at `11` and `26` are the data structures and functions of the
257at `11` and `26` are the data structures and functions of the
210engine; the conclusion is the interface and top-level logic. It
258engine; the conclusion is the interface and top-level logic. It
211produces a gate whose sample is `feed`, a list of `move`.
259produces a gate whose sample is `feed`, a list of `move`.
213Line `2` declares a blank new variable named `game`, whose type
261Line `2` declares a blank new variable named `game`, whose type
214−is the `game` mold (tictactoe game state) defined on line `21`.
262+is the `game` mold (tic-tac-toe game state) defined on line `21`.
215Under line `2`, `game` pulls the variable and `^game` the mold.
263Under line `2`, `game` pulls the variable and `^game` the mold.
217Line `3` enters a loop producing a list of game events, `fact`.
265Line `3` enters a loop producing a list of game events, `fact`.
219Line `4` produces nil, `~`, if `feed` is empty.
267Line `4` produces nil, `~`, if `feed` is empty.
270+ :sip this/(unit fact) :: 5
272+ (~(do go game) i.feed) :: 7
221Lines `5` through `7` apply the move. We open a `go` core on the
275Lines `5` through `7` apply the move. We open a `go` core on the
222current game state, produce a `do` gate, and call that gate on
276current game state, produce a `do` gate, and call that gate on
223the move. The product of the `do` gate is a pair; the head is
277the move. The product of the `do` gate is a pair; the head is
@@ -225,12 +279,23 @@ the move. The product of the `do` gate is a pair; the head is
225`game`. The `:sip` twig declares the head as a new variable,
279`game`. The `:sip` twig declares the head as a new variable,
226`this`; it modifies the subject by setting `game` to the tail.
280`this`; it modifies the subject by setting `game` to the tail.
283+ :var rest/(list fact) :moar(feed t.feed) :: 8
284+ :ifno(this rest [u.this rest]) :: 9
228Line `8` declares a new variable, `rest`, which is all the facts
287Line `8` declares a new variable, `rest`, which is all the facts
229generated by the moves in `t.feed`, the tail of the move list.
288generated by the moves in `t.feed`, the tail of the move list.
230(Yes, this is gratuitous head recursion.) Line `9` produces
289(Yes, this is gratuitous head recursion.) Line `9` produces
231`rest` if the `i.feed` move produced no fact; otherwise it
290`rest` if the `i.feed` move produced no fact; otherwise it
232prepends the new fact to `rest`.
291prepends the new fact to `rest`.
296+ ++ spot {x/atom y/atom} :: 13
234Line `11` wraps a library core around a data structure core, a
299Line `11` wraps a library core around a data structure core, a
235common pattern. (You could put the molds and the gates in the
300common pattern. (You could put the molds and the gates in the
236same core, but the compiler couldn't constant-fold gate samples
301same core, but the compiler couldn't constant-fold gate samples
@@ -241,19 +306,50 @@ A side is a half of the board, as a marked/unmarked bitfield.
242Line `13` defines the `spot` mold, a 2D coordinate.
307Line `13` defines the `spot` mold, a 2D coordinate.
310+ ++ fact :book {$tie $~} :: 14
244Lines `14` to `16` define the `fact` mold, a game event (ie,
315Lines `14` to `16` define the `fact` mold, a game event (ie,
245output action), as a book (tagged union). There are two forms of
316output action), as a book (tagged union). There are two forms of
246`fact`: `[%tie ~]` (reporting a tie), and `[%win cord]`
317`fact`: `[%tie ~]` (reporting a tie), and `[%win cord]`
247(reporting that `'X'` or `'O'` won a game.
318(reporting that `'X'` or `'O'` won a game.
321+ ++ move :book {$x p/spot} :: 17
249Lines `17` to `20` define the `move` mold, a game move. This is
327Lines `17` to `20` define the `move` mold, a game move. This is
250either `[%x spot]`, `[%o spot]`, or `[%z ~]` to reset the board.
328either `[%x spot]`, `[%o spot]`, or `[%z ~]` to reset the board.
331+ ++ game :bank w/? :: 21
252Lines `21` to `23` define the `game` mold, the game state. This
338Lines `21` to `23` define the `game` mold, the game state. This
253is an `a` side, the next side to move; a `z` side, the other
339is an `a` side, the next side to move; a `z` side, the other
254side; and `w`, which is `&` (yes) if `a` is X and `b` is O; `|`
340side; and `w`, which is `&` (yes) if `a` is X and `b` is O; `|`
255otherwise. (Obviously, we swap `a` and `z` on every move.)
341otherwise. (Obviously, we swap `a` and `z` on every move.)
346+ :door half/side :: 28
347+ ++ bit :gate(a/atom =(1 (cut 0 [a 1] half))) :: 29
348+ ++ off :gate(a/spot (add x.a (mul 3 y.a))) :: 30
349+ ++ get :gate(a/spot (bit (off a))) :: 31
350+ ++ set :gate(a/spot (con half (bex (off a)))) :: 32
257Line `26` introduces the library core, which contains the doors
353Line `26` introduces the library core, which contains the doors
258`bo` (for `side` bitfields) and `go` (for game state).
354`bo` (for `side` bitfields) and `go` (for game state).
@@ -271,12 +367,27 @@ Line `32` is the `set` gate, which produces a new side with the
271bit at a `spot` set. It works by ORing (`con`) `half` with the
367bit at a `spot` set. It works by ORing (`con`) `half` with the
272binary exponent (`bex`) of the offset (`off`) of the spot.
368binary exponent (`bex`) of the offset (`off`) of the spot.
371+ ++ win :calt lien :: 33
372+ (rip 4 0wl04h0.4A0Aw.4A00s.0e070) :: 34
373+ :gate(a/atom =(a (dis a half))) :: 35
274Lines `33` to `35` are a victory test. It calls the
377Lines `33` to `35` are a victory test. It calls the
275standard `lien` function, which iterates a boolean gate over a
378standard `lien` function, which iterates a boolean gate over a
276list and produces `&` (yes) if any item tests as true, against a
379list and produces `&` (yes) if any item tests as true, against a
277list of magic bitfields (expanded from a base64 constant), each
380list of magic bitfields (expanded from a base64 constant), each
278of which must equal itself when ANDed (`dis`) with `half`.
381of which must equal itself when ANDed (`dis`) with `half`.
385+ :door game/game :: 38
387+ :gate act/move :: 40
388+ :cast {(unit fact) ^game} :: 41
280Lines `37` to `38` begin the `go` core, a door around a `game`.
391Lines `37` to `38` begin the `go` core, a door around a `game`.
281Again we name the sample `game`. (This is a legitimate style,
392Again we name the sample `game`. (This is a legitimate style,
282but not used much.)
393but not used much.)
@@ -285,11 +396,29 @@ Lines `40` to `42` begin the `do` gate, whose sample is `act`, a
285move. The product is cast to a pair of `(unit fact)` and a new
396move. The product is cast to a pair of `(unit fact)` and a new
286game state, written `^game` to skip to the second binding.
397game state, written `^game` to skip to the second binding.
401+ {$x *} :sure(w.game ~(mo on p.act)) :: 43
402+ {$o *} :deny(w.game ~(mo on p.act)) :: 44
288Lines `42` through `46` switch on the form of `act`. If it's an
408Lines `42` through `46` switch on the form of `act`. If it's an
289`%x` or `%o` move, we assert that it's the right turn, then use
409`%x` or `%o` move, we assert that it's the right turn, then use
290the `mo` door to apply the move. If it's a `%z` move, we clear
410the `mo` door to apply the move. If it's a `%z` move, we clear
291the board.
411the board.
414+ ++ nu :like(game [& 0 0]) :: 48
416+ :door here/spot :: 50
417+ ++ is :or (~(get bo a.game) here) :: 51
418+ (~(get bo z.game) here) :: 52
293Line `48` is the `nu` arm, which produces a blank game state.
422Line `48` is the `nu` arm, which produces a blank game state.
295Lines `49` to `50` begin the `on` door, a door around `here`, a
424Lines `49` to `50` begin the `on` door, a door around `here`, a
@@ -300,6 +429,18 @@ against the combination of game state and coordinate.
300Lines `51` to `53` define the `is` arm, which is `&` (yes) iff
429Lines `51` to `53` define the `is` arm, which is `&` (yes) iff
301either `a` or `z` has played `here`.
430either `a` or `z` has played `here`.
433+ ++ mo :cast {(unit fact) ^game} :: 54
435+ :var next/side (~(set bo a.game) here) :: 56
436+ :if ~(win bo next) :: 57
437+ [[~ %win ?:(w.game %x %o)] nu] :: 58
438+ [~ game(w !w.game, a z.game, z next)] :: 59
303Line `54` begins the `mo` arm, which produces (with a
444Line `54` begins the `mo` arm, which produces (with a
304nonessential cast) a pair of `(unit fact)` and game state.
445nonessential cast) a pair of `(unit fact)` and game state.
305Again we see `^game` to pull the mold, since `game` is the
446Again we see `^game` to pull the mold, since `game` is the