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