on 424cd14 help sign in
454 lines 19 kB history raw
1---
2sort: 9
3title: Examples
4---
6# Examples
8Now we know enough to write two quick examples: the Sieve of
9Eratosthenes (a naive prime sieve) and a tictactoe engine.
11(Note that these are not examples of perfect Hoon code; they are
12meant for teaching. They err, more than usual for Hoon, on the
13side of simple manual construction over high-octane FP.)
15## `sieve`: code in basic style
17A function that produces the list of primes less than or equal to
18than its argument, an atom:
19```
20:gate thru/atom :: 1
21:cast (list atom) :: 2
22:var field/(set atom) (silt (gulf 2 thru)) :: 3
23:rap abet:main :: 4
24:core :: 5
25++ abet :: 6
26 (sort (~(tap in field) ~) lth) :: 7
27:: :: 8
28++ main :: 9
29 :var factor/atom 2 :: 10
30 :loop :like ..main :: 11
31 :if (gth (mul factor factor) thru) :: 12
32 ..main :: 13
33 :moar(factor +(factor), ..main (reap factor)) :: 14
34:: :: 15
35++ reap :: 16
36 :gate factor/atom :: 17
37 :var count/atom (mul 2 factor) :: 18
38 :loop :like ..reap :: 19
39 :if (gth count thru) :: 20
40 ..reap :: 21
41 :moar :: 22
42 count (add count factor) :: 23
43 field (~(del in field) count) :: 24
44 == :: 25
45-- :: 26
46```
48## `sieve`: explanation
50Line `1`: we are building a gate (function) whose sample
51(argument) is `thru`, an atom.
53Line `2`: the product of this gate is a list of atoms.
55Line `3`: we introduce a variable `field`, whose type is a set of
56atoms. The `silt` function converts a list to a set. The `gulf`
57function creates the range `2` through `thru` inclusive, as a
58list of atoms.
60Line `4`: below, we introduce a core which does our work. With
61reverse flow, we compute `main` on this core, then `abet` on the
62product of `main`. (`abet:main` means `:rap(abet main)`.)
64The core is a state machine; `main` produces the core itself,
65with the computation completed. `abet` then extracts the result.
67Line `5`: we wrap a core around our existing subject. The
68`field` and `thru` atoms are within the payload and of course
69remain accessible.
71Lines `6` and `7`: the `abet` arm, which produces the field as a
72sorted list. `in` is the set core; `tap` is an arm which
73produces a gate that exports the set as a list, prepending it to
74a tail which is nil in this case (and most cases). We sort this
75list in ascending order with `lth` (less-than).
77Line `9`: the `main` arm, which performs the main calculation.
79Line `10`: we declare a counter, `factor`, which will iterate
80up through the factors we're removing.
82Line `11`: we start a loop. The product of the loop is cast to
83`..main`, which is the core we're in (`+1.main`).
85Lines `12` and `13`: we terminate the loop, returning `..main`,
86if the square of the counter exceeds the range.
88Line `14`: repeats the loop, incrementing the counter, and
89replacing the core with a version sieved by `reap`.
91Lines `16` and `17`: the `reap` arm, which produces a gate that
92removes multiples of a factor from the field (set of possible
93primes). The sample of this gate is the factor to remove.
95Line `18`: we declare a variable `count`, an atom, with the
96initial value `(mul 2 factor)`.
98Line `19`: we enter a loop. This loop produces the core itself.
100Lines `20` and `21`: we are done if the counter is out of range.
102Lines `22` to `25`: repeat the loop, stepping `count` to the next
103multiple of `factor`, and deleting it from `field`.
105## `sieve`: code in kernel style
107Finally, the same code transliterated into runes (and in a more
108concise "kernel" style).
110```
111|= top/@
112^- (list @)
113=+ fed=(silt (gulf 2 top))
114=< abet:main
115|%
116++ abet (sort (~(tap in fed)) lth)
117++ main
118 =+ fac=2
119 |- ^+ ..main
120 ?: (gth (mul fac fac) top)
121 ..main
122 $(fac +(fac), ..main (reap fac))
123::
124++ reap
125 |= fac/atom
126 =+ cot=(mul 2 fac)
127 |- ^+ ..reap
128 ?: (gth cot top)
129 ..reap
130 $(cot (add cot fac), fed (~(del in fed) cot))
131--
132```
134### `toe`: tictactoe engine
136The `toe` tictactoe engine applies a list of events to a game
137state, producing a list of game actions. Events are tictactoe
138moves (`move)`; actions are tictactoe results (`fact`).
140```
141:rap :gate feed/(list move) :: 1
142 :new game/game :: 2
143 :loop :cast (list fact) :: 3
144 :ifno feed ~ :: 4
145 :sip this/(unit fact) :: 5
146 game :: 6
147 (~(do go game) i.feed) :: 7
148 :var rest/(list fact) :moar(feed t.feed) :: 8
149 :ifno(this rest [u.this rest]) :: 9
150:: :: 10
151:per :core :: 11
152 ++ side atom :: 12
153 ++ spot {x/atom y/atom} :: 13
154 ++ fact :book {$tie $~} :: 14
155 {$win p/cord} :: 15
156 == :: 16
157 ++ move :book {$x p/spot} :: 17
158 {$o p/spot} :: 18
159 {$z $~} :: 19
160 == :: 20
161 ++ game :bank w/? :: 21
162 a/side :: 22
163 z/side :: 23
164 == :: 24
165 -- :: 25
166:core :: 26
167++ bo :: 27
168 :door half/side :: 28
169 ++ bit :gate(a/atom =(1 (cut 0 [a 1] half))) :: 29
170 ++ off :gate(a/spot (add x.a (mul 3 y.a))) :: 30
171 ++ get :gate(a/spot (bit (off a))) :: 31
172 ++ set :gate(a/spot (con half (bex (off a)))) :: 32
173 ++ win :calt lien :: 33
174 (rip 4 0wl04h0.4A0Aw.4A00s.0e070) :: 34
175 :gate(a/atom =(a (dis a half))) :: 35
176 -- :: 36
177++ go :: 37
178 :door game/game :: 38
179 ++ do :: 39
180 :gate act/move :: 40
181 :cast {(unit fact) ^game} :: 41
182 :case act :: 42
183 {$x *} :sure(w.game ~(mo on p.act)) :: 43
184 {$o *} :deny(w.game ~(mo on p.act)) :: 44
185 {$z *} [~ nu] :: 45
186 == :: 46
187 :: :: 47
188 ++ nu :like(game [& 0 0]) :: 48
189 ++ on :: 49
190 :door here/spot :: 50
191 ++ is :or (~(get bo a.game) here) :: 51
192 (~(get bo z.game) here) :: 52
193 == :: 53
194 ++ mo :cast {(unit fact) ^game} :: 54
195 :deny is :: 55
196 :var next/side (~(set bo a.game) here) :: 56
197 :if ~(win bo next) :: 57
198 [[~ %win ?:(w.game %x %o)] nu] :: 58
199 [~ game(w !w.game, a z.game, z next)] :: 59
200 -- :: 60
201 -- :: 62
202-- :: 63
203```
205### `toe`: explanation
207Line `1` wraps a conclusion around a stack of cores. The cores
208at `11` and `26` are the data structures and functions of the
209engine; the conclusion is the interface and top-level logic. It
210produces a gate whose sample is `feed`, a list of `move`.
212Line `2` declares a blank new variable named `game`, whose type
213is the `game` mold (tictactoe game state) defined on line `21`.
214Under line `2`, `game` pulls the variable and `^game` the mold.
216Line `3` enters a loop producing a list of game events, `fact`.
218Line `4` produces nil, `~`, if `feed` is empty.
220Lines `5` through `7` apply the move. We open a `go` core on the
221current game state, produce a `do` gate, and call that gate on
222the move. The product of the `do` gate is a pair; the head is
223`(unit fact)`, either `~` or `[~ fact]`; the tail is a new
224`game`. The `:sip` twig declares the head as a new variable,
225`this`; it modifies the subject by setting `game` to the tail.
227Line `8` declares a new variable, `rest`, which is all the facts
228generated by the moves in `t.feed`, the tail of the move list.
229(Yes, this is gratuitous head recursion.) Line `9` produces
230`rest` if the `i.feed` move produced no fact; otherwise it
231prepends the new fact to `rest`.
233Line `11` wraps a library core around a data structure core, a
234common pattern. (You could put the molds and the gates in the
235same core, but the compiler couldn't constant-fold gate samples
236that use these molds, an efficiency cost.)
238Line `12` defines the `side` mold, an alias for `atom` (`@`).
239A side is a half of the board, as a marked/unmarked bitfield.
241Line `13` defines the `spot` mold, a 2D coordinate.
243Lines `14` to `16` define the `fact` mold, a game event (ie,
244output action), as a book (tagged union). There are two forms of
245`fact`: `[%tie ~]` (reporting a tie), and `[%win cord]`
246(reporting that `'X'` or `'O'` won a game.
248Lines `17` to `20` define the `move` mold, a game move. This is
249either `[%x spot]`, `[%o spot]`, or `[%z ~]` to reset the board.
251Lines `21` to `23` define the `game` mold, the game state. This
252is an `a` side, the next side to move; a `z` side, the other
253side; and `w`, which is `&` (yes) if `a` is X and `b` is O; `|`
254otherwise. (Obviously, we swap `a` and `z` on every move.)
256Line `26` introduces the library core, which contains the doors
257`bo` (for `side` bitfields) and `go` (for game state).
259Lines `27` to `28` begin the `bo` core, a door around `half`, a
260board side.
262Line `29` is the `bit` gate, which tests a bit in `half`.
264Line `30` is the `off` gate, which maps from a `spot` (coordinate)
265to a bit index.
267Line `31` is the `get` gate, which produces the bit at a `spot`.
269Line `32` is the `set` gate, which produces a new side with the
270bit at a `spot` set. It works by ORing (`con`) `half` with the
271binary exponent (`bex`) of the offset (`off`) of the spot.
273Lines `33` to `35` are a victory test. It calls the
274standard `lien` function, which iterates a boolean gate over a
275list and produces `&` (yes) if any item tests as true, against a
276list of magic bitfields (expanded from a base64 constant), each
277of which must equal itself when ANDed (`dis`) with `half`.
279Lines `37` to `38` begin the `go` core, a door around a `game`.
280Again we name the sample `game`. (This is a legitimate style,
281but not used much.)
283Lines `40` to `42` begin the `do` gate, whose sample is `act`, a
284move. The product is cast to a pair of `(unit fact)` and a new
285game state, written `^game` to skip to the second binding.
287Lines `42` through `46` switch on the form of `act`. If it's an
288`%x` or `%o` move, we assert that it's the right turn, then use
289the `mo` door to apply the move. If it's a `%z` move, we clear
290the board.
292Line `48` is the `nu` arm, which produces a blank game state.
294Lines `49` to `50` begin the `on` door, a door around `here`, a
295`spot`. Just as we have multiple computed attributes against the
296game state, we have multiple computed attributes (`is` and `mo`)
297against the combination of game state and coordinate.
299Lines `51` to `53` define the `is` arm, which is `&` (yes) iff
300either `a` or `z` has played `here`.
302Line `54` begins the `mo` arm, which produces (with a
303nonessential cast) a pair of `(unit fact)` and game state.
304Again we see `^game` to pull the mold, since `game` is the
305current game state in the `go` core.
307Line `55` asserts that no one has yet played `here`.
309Line `56` declares a variable `next`, as game side `a` with
310`here` played in it.
312Lines `57` and `58` test if `a` has won with this move. If so,
313we produce the win fact and a blank game state.
315Line `59` produces no fact (since nothing has happened), but
316inverts the `w` turn indicator, replaces side `a` with the other
317side `z`, and replaces `z` with `next`.
319### `toe`: code, kernel style
321```
322=< |= fed/(list move)
323 =| mag/game
324 |- ^- (list fact)
325 ?~ fed ~
326 =^ did/(unit fact) mag (~(do go mag) i.fed)
327 =+ res=$(fed t.fed)
328 ?~(did res [u.did res])
329=> |%
330 ++ side @
331 ++ spot {x/@ y/@}
332 ++ fact $% {$tie $~}
333 {$win p/cord}
334 ==
335 ++ move $% {$x p/spot}
336 {$o p/spot}
337 {$z $~}
338 ==
339 ++ game $: w/?
340 a/side
341 z/side
342 ==
343 --
344|%
345++ bo
346 |_ haf/side
347 ++ bit |=(a/atom =(1 (cut 0 [a 1] haf)))
348 ++ get |=(a/spot (bit (off a)))
349 ++ off |=(a/spot (add x.a (mul 3 y.a)))
350 ++ set |=(a/spot (con haf (bex (off a))))
351 ++ win %+ lien
352 (rip 4 0wl04h0.4A0Aw.4A00s.0e070)
353 |=(a/atom =(a (dis a haf)))
354 --
355++ go
356 |_ mag/game
357 ++ do
358 |= act/move
359 ^- {(unit fact) game}
360 ?- act
361 {$x *} ?>(w.mag ~(mo on p.act))
362 {$o *} ?<(w.mag ~(mo on p.act))
363 {$z *} [~ nu]
364 ==
365 ::
366 ++ nu `game`[& 0 0]
367 ++ on
368 =| her/spot
369 |%
370 ++ is ?| (~(get bo a.mag) her)
371 (~(get bo z.mag) her)
372 ==
373 ++ mo ^- {(unit fact) game}
374 ?< is
375 =+ next=(~(set bo a.mag) her)
376 ?: ~(win bo next)
377 [[~ %win ?:(w.mag %x %o)] nu]
378 [~ mag(w !w.mag, a z.mag, z next)]
379 --
380 --
381--
382```
384## Basic molds
385```
386++ atom @ :: just an atom
387++ axis @ :: tree address
388++ bean ? :: 0=&=yes, 1=|=no
389++ bloq @ :: blockclass
390++ char @tD :: UTF-8 byte
391++ cord @t :: text atom (UTF-8)
392++ gate $-(* *) :: general gate
393++ knot @ta :: ASCII text
394++ noun * :: any noun
395++ null $~ :: null, nil, etc
396++ time @da :: galactic time
397++ path (list knot) :: eg, fs location
398++ tang (list tank) :: error trace
399++ tank ::
400 $% {$leaf p/tape} :: printing formats
401 $: $palm :: backstep list
402 p/{p/tape q/tape r/tape s/tape} ::
403 q/(list tank) ::
404 == ::
405 $: $rose :: flat list
406 p/{p/tape q/tape r/tape} :: mid open close
407 q/(list tank) ::
408 == ::
409 == ::
410++ tanq :: future tank
411 $? {$~ p/(list tanq)} :: list of printables
412 {$~ $~ p/tape} :: simple string
413 (pair @tas tanq) :: captioned
414 == ::
415++ tape (list char) :: string as list
416++ term @tas :: ascii symbol
417++ wall (list tape) :: text lines (no \n)
418++ wain (list cord) :: text lines (no \n)
420::::
421::::
423++ tree |* a/gate :: binary tree
424 $@($~ {n/a l/(tree a) r/(tree a)}) ::
425++ trap |*(a/_* _|?(*a)) :: makes perfect sense
426++ trel |* {a/gate b/gate c/gate} :: just a triple
427 {p/a q/b r/c} ::
428++ each |* {a/gate b/gate} :: either a or b
429 $%({$& p/a} {$| p/b}) :: a default
431++ qual |* {a/gate b/gate c/gate d/gate} :: just a quadruple
432 {p/a q/b r/c s/d} ::
433++ pair |*({a/gate b/gate} {p/a q/b}) :: just a pair
434++ quid |*({a/gate b/*} {a _b}) :: for =^
435++ quip |*({a/gate b/*} {(list a) _b}) :: for =^
436++ unit |* a/gate :: maybe
437 $@($~ {$~ u/a}) ::
438++ list |* a/gate :: null-term list
439 $@($~ {i/a t/(list a)}) ::
440++ lone |*(a/gate p/a) :: just one thing
442::::
443::::
444++ map |* {a/gate b/gate} :: associative tree
445 $@($~ {n/{p/a q/b} l/(map a b) r/(map a b)}) ::
446++ qeu |* a/gate :: queue
447 $@($~ {n/a l/(qeu a) r/(qeu a)}) ::
448++ set |* a/gate :: set
449 $@($~ {n/a l/(set a) r/(set a)}) ::
450++ jar |*({a/gate b/gate} (map a (list b))) :: map of lists
451++ jug |*({a/gate b/gate} (map a (set b))) :: map of sets
452```
454### Basic libraries