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