on 7568a67 help sign in
urbit.org/docs/hoon/examples.md
597 lines 25 kB history raw
1---
2navhome: /docs/
3sort: 17
4title: Examples
5next: true
6---
8# Examples
10Now we know enough to write two quick examples: the Sieve of
11Eratosthenes (a naive prime sieve) and a tic-tac-toe engine.
13(Note that these are not examples of perfect Hoon code; they are
14meant for teaching. They err, more than usual for Hoon, on the
15side of simple manual construction over high-octane FP.)
17## `sieve`: code in basic style
19A function that produces the list of primes less than or equal to
20its argument, an atom:
21```
22:gate thru/atom :: 1
23:cast (list atom) :: 2
24:var field/(set atom) (silt (gulf 2 thru)) :: 3
25:rap abet:main :: 4
26:core :: 5
27++ abet :: 6
28 (sort (~(tap in field) ~) lth) :: 7
29:: :: 8
30++ main :: 9
31 :var factor/atom 2 :: 10
32 :loop :like ..main :: 11
33 :if (gth (mul factor factor) thru) :: 12
34 ..main :: 13
35 :moar(factor +(factor), ..main (reap factor)) :: 14
36:: :: 15
37++ reap :: 16
38 :gate factor/atom :: 17
39 :var count/atom (mul 2 factor) :: 18
40 :loop :like ..reap :: 19
41 :if (gth count thru) :: 20
42 ..reap :: 21
43 :moar :: 22
44 count (add count factor) :: 23
45 field (~(del in field) count) :: 24
46 == :: 25
47-- :: 26
48```
50## `sieve`: explanation
52```
53:gate thru/atom :: 1
54:cast (list atom) :: 2
55:var field/(set atom) (silt (gulf 2 thru)) :: 3
56```
58Line `1`: we are building a gate (function) whose sample
59(argument) is `thru`, an atom.
61Line `2`: the product of this gate is a list of atoms.
63Line `3`: we introduce a variable `field`, whose type is a set of
64atoms. The `silt` function converts a list to a set. The `gulf`
65function creates the range `2` through `thru` inclusive, as a
66list of atoms.
68Line `4`: below, we introduce a core which does our work. With
69reverse flow, we compute `main` on this core, then `abet` on the
70product of `main`. (`abet:main` means `:rap(abet main)`.)
72The core is a state machine; `main` produces the core itself,
73with the computation completed. `abet` then extracts the result.
75```
76:core :: 5
77++ abet :: 6
78 (sort (~(tap in field) ~) lth) :: 7
79```
81Line `5`: we wrap a core around our existing subject. The
82`field` and `thru` atoms are within the payload and of course
83remain accessible.
85Lines `6` and `7`: the `abet` arm, which produces the field as a
86sorted list. `in` is the set core; `tap` is an arm which
87produces a gate that exports the set as a list, prepending it to
88a tail which is nil in this case (and most cases). We sort this
89list in ascending order with `lth` (less-than).
91```
92++ main :: 9
93 :var factor/atom 2 :: 10
94 :loop :like ..main :: 11
95```
97Line `9`: the `main` arm, which performs the main calculation.
99Line `10`: we declare a counter, `factor`, which will iterate
100up through the factors we're removing.
102Line `11`: we start a loop. The product of the loop is cast to
103`..main`, which is the core we're in (`+1.main`).
105```
106 :if (gth (mul factor factor) thru) :: 12
107 ..main :: 13
108 :moar(factor +(factor), ..main (reap factor)) :: 14
109```
111Lines `12` and `13`: we terminate the loop, returning `..main`,
112if the square of the counter exceeds the range.
114Line `14`: repeats the loop, incrementing the counter, and
115replacing the core with a version sieved by `reap`.
117```
118++ reap :: 16
119 :gate factor/atom :: 17
120 :var count/atom (mul 2 factor) :: 18
121```
123Lines `16` and `17`: the `reap` arm, which produces a gate that
124removes multiples of a factor from the field (set of possible
125primes). The sample of this gate is the factor to remove.
127Line `18`: we declare a variable `count`, an atom, with the
128initial value `(mul 2 factor)`.
130```
131 :loop :like ..reap :: 19
132 :if (gth count thru) :: 20
133 ..reap :: 21
134 :moar :: 22
135 count (add count factor) :: 23
136 field (~(del in field) count) :: 24
137 == :: 25
138-- :: 26
139```
141Line `19`: we enter a loop. This loop produces the core itself.
143Lines `20` and `21`: we are done if the counter is out of range.
145Lines `22` to `25`: repeat the loop, stepping `count` to the next
146multiple of `factor`, and deleting it from `field`.
148## `sieve`: code in kernel style
150Finally, the same code transliterated into runes (and in a more
151concise "kernel" style).
153```
154|= top/@
155^- (list @)
156=+ fed=(silt (gulf 2 top))
157=< abet:main
158|%
159++ abet (sort (~(tap in fed)) lth)
160++ main
161 =+ fac=2
162 |- ^+ ..main
163 ?: (gth (mul fac fac) top)
164 ..main
165 $(fac +(fac), ..main (reap fac))
166::
167++ reap
168 |= fac/atom
169 =+ cot=(mul 2 fac)
170 |- ^+ ..reap
171 ?: (gth cot top)
172 ..reap
173 $(cot (add cot fac), fed (~(del in fed) cot))
174--
175```
177### `toe`: tic-tac-toe engine
179The `toe` tic-tac-toe engine applies a list of events to a game
180state, producing a list of game actions. Events are tic-tac-toe
181moves (`move)`; actions are tic-tac-toe results (`fact`).
183```
184:rap :gate feed/(list move) :: 1
185 :new game/game :: 2
186 :loop :cast (list fact) :: 3
187 :ifno feed ~ :: 4
188 :sip this/(unit fact) :: 5
189 game :: 6
190 (~(do go game) i.feed) :: 7
191 :var rest/(list fact) :moar(feed t.feed) :: 8
192 :ifno(this rest [u.this rest]) :: 9
193:: :: 10
194:per :core :: 11
195 ++ side atom :: 12
196 ++ spot {x/atom y/atom} :: 13
197 ++ fact :book {$tie $~} :: 14
198 {$win p/cord} :: 15
199 == :: 16
200 ++ move :book {$x p/spot} :: 17
201 {$o p/spot} :: 18
202 {$z $~} :: 19
203 == :: 20
204 ++ game :bank w/? :: 21
205 a/side :: 22
206 z/side :: 23
207 == :: 24
208 -- :: 25
209:core :: 26
210++ bo :: 27
211 :door half/side :: 28
212 ++ bit :gate(a/atom =(1 (cut 0 [a 1] half))) :: 29
213 ++ off :gate(a/spot (add x.a (mul 3 y.a))) :: 30
214 ++ get :gate(a/spot (bit (off a))) :: 31
215 ++ set :gate(a/spot (con half (bex (off a)))) :: 32
216 ++ win :calt lien :: 33
217 (rip 4 0wl04h0.4A0Aw.4A00s.0e070) :: 34
218 :gate(a/atom =(a (dis a half))) :: 35
219 -- :: 36
220++ go :: 37
221 :door game/game :: 38
222 ++ do :: 39
223 :gate act/move :: 40
224 :cast {(unit fact) ^game} :: 41
225 :case act :: 42
226 {$x *} :sure(w.game ~(mo on p.act)) :: 43
227 {$o *} :deny(w.game ~(mo on p.act)) :: 44
228 {$z *} [~ nu] :: 45
229 == :: 46
230 :: :: 47
231 ++ nu :like(game [& 0 0]) :: 48
232 ++ on :: 49
233 :door here/spot :: 50
234 ++ is :or (~(get bo a.game) here) :: 51
235 (~(get bo z.game) here) :: 52
236 == :: 53
237 ++ mo :cast {(unit fact) ^game} :: 54
238 :deny is :: 55
239 :var next/side (~(set bo a.game) here) :: 56
240 :if ~(win bo next) :: 57
241 [[~ %win ?:(w.game %x %o)] nu] :: 58
242 [~ game(w !w.game, a z.game, z next)] :: 59
243 -- :: 60
244 -- :: 62
245-- :: 63
246```
248### `toe`: explanation
250```
251:rap :gate feed/(list move) :: 1
252 :new game/game :: 2
253 :loop :cast (list fact) :: 3
254 :ifno feed ~ :: 4
255```
257Line `1` wraps a conclusion around a stack of cores. The cores
258at `11` and `26` are the data structures and functions of the
259engine; the conclusion is the interface and top-level logic. It
260produces a gate whose sample is `feed`, a list of `move`.
262Line `2` declares a blank new variable named `game`, whose type
263is the `game` mold (tic-tac-toe game state) defined on line `21`.
264Under line `2`, `game` pulls the variable and `^game` the mold.
266Line `3` enters a loop producing a list of game events, `fact`.
268Line `4` produces nil, `~`, if `feed` is empty.
270```
271 :sip this/(unit fact) :: 5
272 game :: 6
273 (~(do go game) i.feed) :: 7
274```
276Lines `5` through `7` apply the move. We open a `go` core on the
277current game state, produce a `do` gate, and call that gate on
278the move. The product of the `do` gate is a pair; the head is
279`(unit fact)`, either `~` or `[~ fact]`; the tail is a new
280`game`. The `:sip` twig declares the head as a new variable,
281`this`; it modifies the subject by setting `game` to the tail.
283```
284 :var rest/(list fact) :moar(feed t.feed) :: 8
285 :ifno(this rest [u.this rest]) :: 9
286```
288Line `8` declares a new variable, `rest`, which is all the facts
289generated by the moves in `t.feed`, the tail of the move list.
290(Yes, this is gratuitous head recursion.) Line `9` produces
291`rest` if the `i.feed` move produced no fact; otherwise it
292prepends the new fact to `rest`.
294```
295:per :core :: 11
296 ++ side atom :: 12
297 ++ spot {x/atom y/atom} :: 13
298```
300Line `11` wraps a library core around a data structure core, a
301common pattern. (You could put the molds and the gates in the
302same core, but the compiler couldn't constant-fold gate samples
303that use these molds, an efficiency cost.)
305Line `12` defines the `side` mold, an alias for `atom` (`@`).
306A side is a half of the board, as a marked/unmarked bitfield.
308Line `13` defines the `spot` mold, a 2D coordinate.
310```
311 ++ fact :book {$tie $~} :: 14
312 {$win p/cord} :: 15
313 == :: 16
314```
316Lines `14` to `16` define the `fact` mold, a game event (i.e.,
317output action), as a book (tagged union). There are two forms of
318`fact`: `[%tie ~]` (reporting a tie), and `[%win cord]`
319(reporting that `'X'` or `'O'` won a game.
321```
322 ++ move :book {$x p/spot} :: 17
323 {$o p/spot} :: 18
324 {$z $~} :: 19
325 == :: 20
326```
328Lines `17` to `20` define the `move` mold, a game move. This is
329either `[%x spot]`, `[%o spot]`, or `[%z ~]` to reset the board.
331```
332 ++ game :bank w/? :: 21
333 a/side :: 22
334 z/side :: 23
335 == :: 24
336 -- :: 25
337```
339Lines `21` to `23` define the `game` mold, the game state. This
340is an `a` side, the next side to move; a `z` side, the other
341side; and `w`, which is `&` (yes) if `a` is X and `b` is O; `|`
342otherwise. (Obviously, we swap `a` and `z` on every move.)
344```
345:core :: 26
346++ bo :: 27
347 :door half/side :: 28
348 ++ bit :gate(a/atom =(1 (cut 0 [a 1] half))) :: 29
349 ++ off :gate(a/spot (add x.a (mul 3 y.a))) :: 30
350 ++ get :gate(a/spot (bit (off a))) :: 31
351 ++ set :gate(a/spot (con half (bex (off a)))) :: 32
352```
354Line `26` introduces the library core, which contains the doors
355`bo` (for `side` bitfields) and `go` (for game state).
357Lines `27` to `28` begin the `bo` core, a door around `half`, a
358board side.
360Line `29` is the `bit` gate, which tests a bit in `half`.
362Line `30` is the `off` gate, which maps from a `spot` (coordinate)
363to a bit index.
365Line `31` is the `get` gate, which produces the bit at a `spot`.
367Line `32` is the `set` gate, which produces a new side with the
368bit at a `spot` set. It works by ORing (`con`) `half` with the
369binary exponent (`bex`) of the offset (`off`) of the spot.
371```
372 ++ win :calt lien :: 33
373 (rip 4 0wl04h0.4A0Aw.4A00s.0e070) :: 34
374 :gate(a/atom =(a (dis a half))) :: 35
375 -- :: 36
376```
378Lines `33` to `35` are a victory test. It calls the
379standard `lien` function, which iterates a boolean gate over a
380list and produces `&` (yes) if any item tests as true, against a
381list of magic bitfields (expanded from a base64 constant), each
382of which must equal itself when ANDed (`dis`) with `half`.
384```
385++ go :: 37
386 :door game/game :: 38
387 ++ do :: 39
388 :gate act/move :: 40
389 :cast {(unit fact) ^game} :: 41
390```
392Lines `37` to `38` begin the `go` core, a door around a `game`.
393Again we name the sample `game`. (This is a legitimate style,
394but not used much.)
396Lines `40` to `42` begin the `do` gate, whose sample is `act`, a
397move. The product is cast to a pair of `(unit fact)` and a new
398game state, written `^game` to skip to the second binding.
400```
401 :case act :: 42
402 {$x *} :sure(w.game ~(mo on p.act)) :: 43
403 {$o *} :deny(w.game ~(mo on p.act)) :: 44
404 {$z *} [~ nu] :: 45
405 == :: 46
406 :: :: 47
407```
409Lines `42` through `46` switch on the form of `act`. If it's an
410`%x` or `%o` move, we assert that it's the right turn, then use
411the `mo` door to apply the move. If it's a `%z` move, we clear
412the board.
414```
415 ++ nu :like(game [& 0 0]) :: 48
416 ++ on :: 49
417 :door here/spot :: 50
418 ++ is :or (~(get bo a.game) here) :: 51
419 (~(get bo z.game) here) :: 52
420 == :: 53
421```
423Line `48` is the `nu` arm, which produces a blank game state.
425Lines `49` to `50` begin the `on` door, a door around `here`, a
426`spot`. Just as we have multiple computed attributes against the
427game state, we have multiple computed attributes (`is` and `mo`)
428against the combination of game state and coordinate.
430Lines `51` to `53` define the `is` arm, which is `&` (yes) iff
431either `a` or `z` has played `here`.
433```
434 ++ mo :cast {(unit fact) ^game} :: 54
435 :deny is :: 55
436 :var next/side (~(set bo a.game) here) :: 56
437 :if ~(win bo next) :: 57
438 [[~ %win ?:(w.game %x %o)] nu] :: 58
439 [~ game(w !w.game, a z.game, z next)] :: 59
440 -- :: 60
441 -- :: 62
442-- :: 63
443```
445Line `54` begins the `mo` arm, which produces (with a
446nonessential cast) a pair of `(unit fact)` and game state.
447Again we see `^game` to pull the mold, since `game` is the
448current game state in the `go` core.
450Line `55` asserts that no one has yet played `here`.
452Line `56` declares a variable `next`, as game side `a` with
453`here` played in it.
455Lines `57` and `58` test if `a` has won with this move. If so,
456we produce the win fact and a blank game state.
458Line `59` produces no fact (since nothing has happened), but
459inverts the `w` turn indicator, replaces side `a` with the other
460side `z`, and replaces `z` with `next`.
462### `toe`: code, kernel style
464```
465=< |= fed/(list move)
466 =| mag/game
467 |- ^- (list fact)
468 ?~ fed ~
469 =^ did/(unit fact) mag (~(do go mag) i.fed)
470 =+ res=$(fed t.fed)
471 ?~(did res [u.did res])
472=> |%
473 ++ side @
474 ++ spot {x/@ y/@}
475 ++ fact $% {$tie $~}
476 {$win p/cord}
477 ==
478 ++ move $% {$x p/spot}
479 {$o p/spot}
480 {$z $~}
481 ==
482 ++ game $: w/?
483 a/side
484 z/side
485 ==
486 --
487|%
488++ bo
489 |_ haf/side
490 ++ bit |=(a/atom =(1 (cut 0 [a 1] haf)))
491 ++ get |=(a/spot (bit (off a)))
492 ++ off |=(a/spot (add x.a (mul 3 y.a)))
493 ++ set |=(a/spot (con haf (bex (off a))))
494 ++ win %+ lien
495 (rip 4 0wl04h0.4A0Aw.4A00s.0e070)
496 |=(a/atom =(a (dis a haf)))
497 --
498++ go
499 |_ mag/game
500 ++ do
501 |= act/move
502 ^- {(unit fact) game}
503 ?- act
504 {$x *} ?>(w.mag ~(mo on p.act))
505 {$o *} ?<(w.mag ~(mo on p.act))
506 {$z *} [~ nu]
507 ==
508 ::
509 ++ nu `game`[& 0 0]
510 ++ on
511 =| her/spot
512 |%
513 ++ is ?| (~(get bo a.mag) her)
514 (~(get bo z.mag) her)
515 ==
516 ++ mo ^- {(unit fact) game}
517 ?< is
518 =+ next=(~(set bo a.mag) her)
519 ?: ~(win bo next)
520 [[~ %win ?:(w.mag %x %o)] nu]
521 [~ mag(w !w.mag, a z.mag, z next)]
522 --
523 --
524--
525```
527## Basic molds
528```
529++ atom @ :: just an atom
530++ axis @ :: tree address
531++ bean ? :: 0=&=yes, 1=|=no
532++ bloq @ :: blockclass
533++ char @tD :: UTF-8 byte
534++ cord @t :: text atom (UTF-8)
535++ gate $-(* *) :: general gate
536++ knot @ta :: ASCII text
537++ noun * :: any noun
538++ null $~ :: null, nil, etc
539++ time @da :: galactic time
540++ path (list knot) :: eg, fs location
541++ tang (list tank) :: error trace
542++ tank ::
543 $% {$leaf p/tape} :: printing formats
544 $: $palm :: backstep list
545 p/{p/tape q/tape r/tape s/tape} ::
546 q/(list tank) ::
547 == ::
548 $: $rose :: flat list
549 p/{p/tape q/tape r/tape} :: mid open close
550 q/(list tank) ::
551 == ::
552 == ::
553++ tanq :: future tank
554 $? {$~ p/(list tanq)} :: list of printables
555 {$~ $~ p/tape} :: simple string
556 (pair @tas tanq) :: captioned
557 == ::
558++ tape (list char) :: string as list
559++ term @tas :: ascii symbol
560++ wall (list tape) :: text lines (no \n)
561++ wain (list cord) :: text lines (no \n)
563::::
564::::
566++ tree |* a/gate :: binary tree
567 $@($~ {n/a l/(tree a) r/(tree a)}) ::
568++ trap |*(a/_* _|?(*a)) :: makes perfect sense
569++ trel |* {a/gate b/gate c/gate} :: just a triple
570 {p/a q/b r/c} ::
571++ each |* {a/gate b/gate} :: either a or b
572 $%({$& p/a} {$| p/b}) :: a default
574++ qual |* {a/gate b/gate c/gate d/gate} :: just a quadruple
575 {p/a q/b r/c s/d} ::
576++ pair |*({a/gate b/gate} {p/a q/b}) :: just a pair
577++ quid |*({a/gate b/*} {a _b}) :: for =^
578++ quip |*({a/gate b/*} {(list a) _b}) :: for =^
579++ unit |* a/gate :: maybe
580 $@($~ {$~ u/a}) ::
581++ list |* a/gate :: null-term list
582 $@($~ {i/a t/(list a)}) ::
583++ lone |*(a/gate p/a) :: just one thing
585::::
586::::
587++ map |* {a/gate b/gate} :: associative tree
588 $@($~ {n/{p/a q/b} l/(map a b) r/(map a b)}) ::
589++ qeu |* a/gate :: queue
590 $@($~ {n/a l/(qeu a) r/(qeu a)}) ::
591++ set |* a/gate :: set
592 $@($~ {n/a l/(set a) r/(set a)}) ::
593++ jar |*({a/gate b/gate} (map a (list b))) :: map of lists
594++ jug |*({a/gate b/gate} (map a (set b))) :: map of sets
595```
597### Basic libraries