on master help sign in
adds workbook
commit0904477a1352c1760763d4a1e072fd3196446e49 authorRobert <robert@tlon.io> dateTue 22 Jan 2019, 15:04 (8 years ago) parenta556e45
7 files changed+1156
learn/arvo/workbook.udon+23 learn/arvo/workbook/bomb.udon+143 learn/arvo/workbook/caesar.udon+359 learn/arvo/workbook/digits.udon+116 learn/arvo/workbook/eightball.udon+161 learn/arvo/workbook/recursion.udon+196 learn/arvo/workbook/traffic-light.udon+158
learn/arvo/workbook.udonnew file+23
@@ -0,0 +1,23 @@
1+:- :~ navhome/'/docs/'
2+ navuptwo/'true'
3+ sort/'6'
4+ title/'Hoon Workbook'
5+ ==
6+;>
7+
8+# Hoon Workbook
9+
10+The Workbook is the place to sharpen your Hoon skills. Each entry in the
11+Workbook is a code walkthrough followed by exercises.
12+
13+- The [Caesar Cipher](/docs/learn/arvo/workbook/caesar) shows you how to build a simple method of message obfuscation.
14+
15+- The [Recursion](/docs/learn/arvo/workbook/recursion) walkthrough will explain common patterns of recursion in programming and how to implement them in Hoon.
16+
17+- The [Digits](/docs/learn/arvo/workbook/digits) example demonstrates how to decompose a number into a list of its digits.
18+
19+- The [Magic 8-Ball](/docs/learn/arvo/workbook/eightball) example emulates everyone's favorite decision-making machine.
20+
21+- The [Traffic-light](/docs/learn/arvo/workbook/traffic-light) example demonstrates how to creates a state machine in Hoon.
22+
23+- The [Bomb-defusing](/docs/learn/arvo/workbook/bomb) exercise shows how to program, well, a bomb-defusing scenario.
learn/arvo/workbook/bomb.udonnew file+143
@@ -0,0 +1,143 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'6'
4+ title/'Bomb Defusing'
5+ ==
6+;>
7+
8+# Bomb Defusing
9+
10+In this exercise, we will build a generator that takes a list of wires to be cut
11+in order to defuse a bomb. The bomb is defused according to the following rules.
12+
13+There are 6 possible colors of wire: white, black, purple, red, green, and
14+orange.
15+
16+If you cut a white cable, you cannot cut white or black cable.
17+
18+If you cut a red cable, you must cut a green cable.
19+
20+If you cut a black cable, you cannot cut a white, green, or orange cable.
21+
22+If you cut an orange cable, you must cut a red or cable.
23+
24+If you cut a green cable, you must cut an orange or white cable.
25+
26+If you cut a purple cable, you cannot cut a purple, green, orange, or white
27+cable.
28+
29+If the list of cuts does not result in the bomb exploding, the output should be
30+a tape `bomb defused`. If any of the rules were broken, it should output the
31+tape `boom`.
32+
33+
34+```
35+!:
36+:- %say
37+|= [* [cuts=(list tape) ~] ~]
38+:- %noun
39+=<
40+(defuse cuts)
41+|%
42+++ defuse
43+ |= cuts=(list tape)
44+ =| bad=(list tape)
45+ |-
46+ ?~ cuts
47+ "bomb defused"
48+ =/ cut i.cuts
49+ ?~ bad
50+ $(bad (~(got by rules) cut), cuts t.cuts)
51+ ?~ (find [cut ~] bad)
52+ $(bad (~(got by rules) cut), cuts t.cuts)
53+ "boom"
54+++ rules
55+ %- ~(gas by *(map tape (list tape)))
56+ :~ :- "white"
57+ :~ "white"
58+ "black"
59+ ==
60+ :- "red"
61+ :~ "white"
62+ "red"
63+ "black"
64+ "orange"
65+ "purple"
66+ ==
67+ :- "black"
68+ :~ "white"
69+ "green"
70+ "orange"
71+ ==
72+ :- "orange"
73+ :~ "white"
74+ "orange"
75+ "green"
76+ "purple"
77+ ==
78+ :- "green"
79+ :~ "red"
80+ "black"
81+ "green"
82+ "purple"
83+ ==
84+ :- "purple"
85+ :~ "purple"
86+ "green"
87+ "orange"
88+ "white"
89+ ==
90+ ==
91+--
92+```
93+
94+The start of our generator is simple enough. The `!:` in the first line enables
95+a full stack trace in the event of an error. The following three lines create a
96+`%say` generator that takes a list of tape as an argument.
97+
98+We next use the `=<` rune to compose two hoons, inverted. Remember that it's
99+good Hoon style is to have the heaviest parts to the bottom -- that's what we're
100+doing here.
101+
102+We call `defuse` and pass it `cuts`, the list of tapes we were provided with
103+when the generator started.
104+
105+Next is the core that has two arms, `defuse` and `rules`. Let's look at `rules`
106+quickly.
107+
108+We can see that it is a `map` of `tape` to `list` of `tape`. For each of the
109+rules above we have specified when you cut a wire, which of the other wires you
110+cannot cut. This required some reformulating of the rules given to use at the
111+start, but it is much simpler to work with.
112+
113+```
114+++ defuse
115+ |= cuts=(list tape)
116+ =| bad=(list tape)
117+ |-
118+ ?~ cuts
119+ "bomb defused"
120+ =/ cut i.cuts
121+ ?~ bad
122+ $(bad (~(got by rules) cut), cuts t.cuts)
123+ ?~ (find [cut ~] bad)
124+ $(bad (~(got by rules) cut), cuts t.cuts)
125+ "boom"
126+```
127+
128+The `defuse` arm is the meat of our program. It is a `gate` that takes a `list`
129+of `tape`. We combine a defaulted `list` of `tape` with the face `bad` with the
130+subject.
131+
132+If `cuts` is empty, the bomb has been successfully defused.
133+
134+Otherwise, we give `i.cuts`, the first item in the list, a face called `cut`.
135+
136+If `bad` is empty, we recurse. This recursion sets `bad` to be the list of
137+wires we can not cut from the `rules` map and make `cuts` `t.cuts` or the tail
138+of `cuts`, removing the first element of the list.
139+
140+If `bad` is not empty, we want to search inside of it for the current `cut`. If
141+it's not listed, then we are safe to continue and recurse to process the rest of
142+the cuts. However, if it is found in the bad list, the user has failed and the
143+bomb explodes.
learn/arvo/workbook/caesar.udonnew file+359
@@ -0,0 +1,359 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'1'
4+ title/'Caesar Cipher'
5+ ==
6+;>
7+
8+# Caesar Cipher
9+
10+A Caesar cipher is a very simple way to obfuscate a message. The technique
11+takes a string and swaps out each component letter with another letter that is
12+a specified number of positions up or down in the alphabet. For example, with a
13+"right-shift" of 1, `a` would become `b`, `j` would become `k`, and `z` would
14+wrap around back to `a`.
15+
16+Consider the message below, and the cipher that results when we Caesar-shift the
17+message to the right by 1.
18+
19+```
20+Plaintext message: "do not give way to anger"
21+Right-shifted cipher: "ep opu hjwf xbz up bohfs"
22+```
23+
24+Note that the Caesar cipher is completely unsuitable for actually securing
25+information. Implementing it in a program is just a fun exercise.
26+
27+### A Caesar Cipher In Hoon
28+
29+Below is a generator that performs a Caesar cipher on a tape. This example
30+isn't the most compact implementation of such a cipher in Hoon, but it
31+demonstrates important principles that more laconic code would not. Save it as
32+`caesar.hoon` in your `/gen` directory.
33+
34+```
35+!:
36+:- %say
37+=+ ^= caesar
38+ |%
39+ ++ alpha "abcdefghijklmnopqrstuvwxyz"
40+ ++ shift
41+ |= [message=tape key=@ud]
42+ (operate message key (encoder key))
43+ ++ unshift
44+ |= [message=tape key=@ud]
45+ (operate message key (decoder key))
46+ ++ operate
47+ |= [message=tape key=@ud encoder=(map @t @t)]
48+ ^- tape
49+ %+ turn message
50+ |= a=@t
51+ (~(got by encoder) a)
52+ ++ encoder
53+ |= [key=@ud]
54+ =/ keytape=tape (rott alpha key)
55+ (coder alpha keytape)
56+ ++ decoder
57+ |= [key=@ud]
58+ =/ keytape=tape (rott alpha key)
59+ (coder keytape alpha)
60+ ++ coder
61+ |= [a=tape b=tape]
62+ (~(put by (zipper a b)) ' ' ' ')
63+ ++ zipper
64+ |= [a=tape b=tape]
65+ ^- (map @t @t)
66+ =| chart=(map @t @t)
67+ ?. =((lent a) (lent b))
68+ ~| %uneven-lengths !!
69+ |-
70+ ?: |(?=(~ a) ?=(~ b))
71+ chart
72+ $(chart (~(put by chart) i.a i.b), a t.a, b t.b)
73+ ++ rott
74+ |= [m=tape n=@ud]
75+ =/ length=@ud (lent m)
76+ =+ s=(trim (mod n length) m)
77+ (weld q.s p.s)
78+ --
79+|= [* [msg=tape key=@ud ~] ~]
80+:- %noun
81+=. msg (cass msg)
82+:- (shift.caesar msg key)
83+(unshift.caesar msg key)
84+```
85+
86+This generator takes two arguments: a `tape`, which is your plaintext message,
87+and an unsigned integer, which is the shift-value of the cipher. It produces
88+a cell of two `tapes`: one that has been shifted right by the value, and another
89+that has been shifted left. It also converts any uppercase input into lowercase.
90+
91+Try it out in the Dojo:
92+
93+```
94+> +caesar "test" 2
95+["vguv" "rcqr"]
96+
97+> +caesar "test" 26
98+["test" "test"]
99+
100+> +caesar "test" 28
101+["vguv" "rcqr"]
102+
103+> +caesar "test" 104
104+["test" "test"]
105+
106+> +caesar "tESt" 2
107+["vguv" "rcqr"]
108+
109+> +caesar "test!" 2
110+nest-fail
111+
112+```
113+
114+##### Examining Our Code
115+
116+Let's examine our `caesar.hoon` code piece by piece. We won't necessarily go
117+in written order; instead, we'll cover code in the intuitive order of the
118+program. For each chunk that we cover, try to read and understand the code
119+itself before reading the explanation.
120+
121+```
122+!:
123+:- %say
124+=+ ^= caesar
125+ |%
126+```
127+
128+The `!:` in the first line of the above code enables a full stack trace in the
129+event of an error.
130+
131+`:- %say` begins to construct a cell with `%say` as the head, and the code that
132+follows as the tail. This causes the Arvo to interpret the file as a
133+[`%say` generator](/docs/tutorials/generators).
134+
135+`=+` adds a noun the subject, `=^ caesar` names that noun, and `|%` is used
136+to create a core that contains the following arms. This results in having a core
137+with the face `caesar` that we can call.
138+
139+Now let's look at the rest of the program that is outside of our core:
140+
141+```
142+|= [* [msg=tape key=@ud ~] ~]
143+:- %noun
144+=. msg (cass msg)
145+:- (shift.caesar msg key)
146+(unshift.caesar msg key)
147+```
148+
149+The top line creates a gate with `|=`. The sample of that gate follows the
150+scheme used by `%say` generators: it's a 3-tuple whose parts allow for different
151+kinds of data. We only need non-optional arguments, though, so we only fill in
152+the second part. There we take a `msg` argument and a `key` argument. We use a
153+`*` and a `~` in the first part (Arvo data) and third part (optional arguments),
154+respectively, because we aren't using them here. See the
155+[generator documentation](/docs/tutorials/generators) for more information.
156+
157+`:- %noun` simply labels the output of this program as the `%noun` mark.
158+
159+`=. msg (cass msg)` changes the input string `msg` to lowercases. `=.` changes
160+the leg of the subject to something else. In our case, the leg to be changed is
161+`msg`, and the thing to replace it is `(cass msg)`. `cass` is a standard-library
162+gate that converts uppercase letters to lowercase.
163+
164+`:- (shift.caesar msg key)` and `(unshift.caesar msg key)` simply composes a
165+cell of a right-shifted cipher and a left-shifted cell. This is the final output
166+of our generator.
167+
168+```
169+ ++ rott
170+ |= [m=tape n=@ud]
171+ =/ length=@ud (lent m)
172+ =+ s=(trim (mod n length) m)
173+ (weld q.s p.s)
174+```
175+
176+The `rott` arm takes takes a specified number of characters off of a tape and
177+puts them on the end of the tape.
178+
179+`|= [m=tape n=@ud]` creates a gate that takes two arguments: `m`, a `tape`,
180+and `n`, a `@ud`.
181+
182+`=/ length=@ud (lent m)` stores the length of `m` to make the following
183+code a little clearer.
184+
185+`trim` is a a gate from the standard library that splits a tape at into two
186+parts at a specified position. So `=+ s=(trim (mod n length) m)` splits the
187+tape `m` into two parts, `p` and `q`, and stores it in `s`. We call the modulus
188+operation `mod` to make sure that we split our `tape` at the correct place, even
189+if `n` is larger than `length`.
190+
191+`(weld q.s p.s)` uses `weld`, which combines two strings into one. In this
192+instance, we are switching the two parts: the second part `q.s` is welded to the
193+front, and the first part `p.s` is welded to the back.
194+
195+```
196+ ++ zipper
197+ |= [a=tape b=tape]
198+ ^- (map @t @t)
199+ =| chart=(map @t @t)
200+ ?. =((lent a) (lent b))
201+ ~| %uneven-lengths !!
202+ |-
203+ ?: |(?=(~ a) ?=(~ b))
204+ chart
205+ $(chart (~(put by chart) i.a i.b), a t.a, b t.b)
206+```
207+
208+The `zipper` arm takes two tapes and creates a `map` out of them -- an
209+an association between their elements.
210+
211+So then if `tapes` are easier to manipulate, why then are we producing `cords`?
212+In this case what we are going to to be doing is mapping a single element of a `
213+tape` to another element of a `tape`, which as we have established as being a
214+`cord`. This will simplify our use of this method and we don't need to
215+manipulate the keys or values, simply look them up.
216+
217+`|= [a=tape b=tape]` builds a gate that takes two tapes, `a` and `b`, as its
218+sample.
219+
220+`^- (map @t @t)` casts the gate to a `map` with a `cord` key and a `cord`
221+value. A `map` is a type equivalent to a dictionary in other languages: it's a
222+data structure that associates a key with a value. If, for example, we wanted
223+to have an association between `a` and 1 and `b` and 2, we could use a `map`.
224+
225+`=| chart=(map @t @t)` adds a noun to the subject with the default value of
226+the `(map @t @t)` type, and gives that noun the face `chart`.
227+
228+`?. =((lent a) (lent b))` checks if the two tapes are the same length. If not,
229+the program crashes.
230+
231+`|-` creates a trap, a gate that is called immediately.
232+
233+`?: |(?=(~ a) ?=(~ b))` checks if either tape is empty. If this is true, we
234+the program is finished and can return `chart`, the the `map` that we have been
235+creating.
236+
237+If the above test finds that its condition to be false, we trigger a recursion
238+that constructs our `map`: $(chart (~(put by chart) i.a i.b), a t.a, b t.b)`.
239+This code recursively adds an entry in our `map` where the head of the tape `a`
240+maps to the value of the head of tape `b` with `~(put by chart)`, our calling
241+of the `put` arm of the `by` map-engien core. The recursion also "consumes"
242+those heads with every iteration by changing `a` and `b` to their tails.
243+
244+Perhaps now you can understand why this arm is named `zipper`. It's putting two
245+tapes together by matching pieces from each side, something akin to a jacket zipper.
246+
247+We have three related arms to look at next, `coder`, `encoder`, and
248+`decoder`. `coder` is the foundation of the other two, so we'll look at it
249+first.
250+
251+```
252+ ++ coder
253+ |= [a=tape b=tape]
254+ (~(put by (zipper a b)) ' ' ' ')
255+```
256+
257+`|= [a=tape b=tape]` creates a gate that takes two `tapes`.
258+
259+We use `put by` on the next line, giving it a `map` produced by the `zipper`
260+arm that we created before. This adds an entry to the map where the space
261+character (called `ace`) simply maps to itself. This is done to simplify
262+the handling of spaces in `tapes` we want to encode, since we don't want to
263+shift them.
264+
265+```
266+ ++ encoder
267+ |= [key=@ud]
268+ =/ keytape=tape (rott alpha key)
269+ (coder alpha keytape)
270+ ++ decoder
271+ |= [key=@ud]
272+ =/ keytape=tape (rott alpha key)
273+ (coder keytape alpha)
274+```
275+
276+`encoder` and `decoder` are implemented in terms of the `coder` arm. These gates
277+are essentially identical, with the arguments reversed. They simplify the two
278+common transactions you want to do in this program: producing `maps` that we can
279+use to encode and decode messages.
280+
281+In both cases, we create a gate that accepts a `@ud` named `key`.
282+
283+`=/ keytape=tape (rott alpha key)` creates a `keytape` noun by calling `rott`
284+on `alpha` our `key` input. `alpha` is our arm which contains a `tape` of the
285+entire alphabet.
286+
287+`(coder alpha keytape)`, for `encoder`, and `(coder keytape alpha)`, for
288+`decoder`, produce a `map` that has the first argument as the keys and the
289+second as the values.
290+
291+If our two inputs to `coder` were `"abcdefghijklmnopqrstuvwxyz"` and
292+`"bcdefghijklmnopqrstuvwxyza"` We would get a `map` where `'a'` maps to `'b'`,
293+`'b'` to `'c'` and so on. By doing this we can produce a `map` that gives us a
294+translation between the alphabet and our shifted alphabet, or vice versa.
295+
296+Still with us? Good. We are finally about to use all the stuff that we've
297+walked through.
298+
299+```
300+ ++ shift
301+ |= [message=tape key=@ud]
302+ (operate message key (encoder key))
303+ ++ unshift
304+ |= [message=tape key=@ud]
305+ (operate message key (decoder key))
306+```
307+
308+Both `shift` and `unshift` take two arguments: our `message`, the `tape` that we
309+want to manipulate; and our `key`, the value that we want to shift our message
310+by.
311+
312+`shift` is for encoding, and `unshift` is for decoding. Thus, `shift` calls the
313+`operate` arm with `(operate message key (encoder key))`, and `unshift` makes
314+that call with `(operate message key (decoder key))`. These both produce the
315+final output of the core, to be called in the form of `(shift.caesar msg key)`
316+and `(unshift.caesar msg key)` at the bottom of the program.
317+
318+```
319+++ operate
320+ |= [message=tape key=@ud encoder=(map @t @t)]
321+ ^- tape
322+ %+ turn message
323+ |= a=@t
324+ (~(got by encoder) a)
325+```
326+
327+`operate` produces a `tape`. The `%+` rune allows us to pull an arm
328+with a pair sample. The arm we are going to pull is `turn`. This arm
329+takes two arguments, a `list` and a `gate` to apply to each element of the
330+`list`.
331+
332+If we then give our arm Caesar's famous statement, and get our left- and
333+right-ciphers.
334+
335+```
336+> +caesar "i came i saw i conquered" 4
337+["m geqi m wea m gsruyivih" "e ywia e ows e ykjmqanaz"]
338+```
339+
340+Now, to decode, we can put either of our ciphers in with the appropriate key and
341+look for the legible result.
342+
343+```
344+> +caesar "m geqi m wea m gsruyivih" 4
345+["q kium q aie q kwvycmzml" "i came i saw i conquered"]
346+
347+> +caesar "e ywia e ows e ykjmqanaz" 4
348+["i came i saw i conquered" "a usew a kso a ugfimwjwv"]
349+```
350+
351+### Exercises
352+
353+
354+1. Take the example generator and modify it to add a second layer of shifts.
355+
356+2. Extend the example generator to allow for using characters other than a-z.
357+
358+3. Build a gate that can take a Caesar shifted `tape` and produce
359+possible unshifted `tapes`.
learn/arvo/workbook/digits.udonnew file+116
@@ -0,0 +1,116 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'3'
4+ title/'Digits'
5+ ==
6+;>
7+
8+# Digits
9+
10+Let's write a generator that takes a `@ud` (unsigned decimal) and returns a list
11+of its digits.
12+
13+```
14+!:
15+:- %say
16+|= [* [n=@ud ~] ~]
17+:- %noun
18+=| lis=(list @ud)
19+|- ^+ lis
20+?: (lte n 0)
21+ lis
22+%= $
23+ n (div n 10)
24+ lis (mod n 10)^lis
25+==
26+```
27+
28+We're creating a [`%say` generator](/docs/tutorials/generators). That means we
29+need some "boilerplate" code in the format of `[%say [%noun "data"]]`:
30+
31+```
32+:- %say
33+|= [* [n=@ud ~] ~]
34+:- %noun
35+```
36+
37+The head of this cell is the literal `%say`.
38+
39+In the tail is the gate and its sample: `|= [* [n=@ud ~] ~]`. This is
40+where we describe any arguments we are expecting to be passed in when the
41+generator is called. We are expecting data of type `@ud`. We give the data the
42+face `n` so that we can easily reference it later.
43+
44+Also in the tail is another `cell`, its head indicating to the `dojo` how to
45+print the value we are creating. In this case, we use the generic `%noun`.
46+
47+The tail of our second cell is the product of the rest of the program.
48+
49+```
50+=| lis=(list @ud)
51+```
52+
53+We use the above code to construct a `list` of `@ud` by cutting up the `@ud` we
54+got passed and so we add a face onto that type. This list is empty until we
55+manipulate it further.
56+
57+```
58+|- ^+ lis
59+?: (lte n 0)
60+ lis
61+```
62+
63+`|-` creates a gate that functions as a recursion point.
64+
65+We are actually able to reuse `lis` for the type of output that we are going
66+to produce. A sibling of the `^-` rune, `^+` is distinct because it is for
67+casting _by example_. It takes type information from an _instance_ of that type.
68+It's useful when using a complicated type.
69+
70+```
71+?: (lte n 0)
72+ lis
73+```
74+
75+`?:` checks if the statement that follows is true or false. In our case, if it's
76+true that `n` is less than or equal to `0`, we simply return `lis`. Otherwise,
77+we branch to the following operations:
78+
79+```
80+%= $
81+ n (div n 10)
82+ lis (mod n 10)^lis
83+==
84+```
85+
86+`%=` is the rune that takes a wing with any number changes, in the
87+form of a list. Our list has two elements that represent such changes, contained
88+in a `$` expression to perform recursion. This is the tall form of an equivalent
89+syntax that you may be more familiar with:
90+`$(n (div n 10), lis (mod n 10)^lis)`.
91+
92+The first change divides `n` by `10`, rounding down without a remainder, and
93+assigning that product as the new value for `n`.
94+
95+The second change prepends the remainder of `n` divided `10` to `lis` (`x^y` is
96+an alternative syntax for `[x y]`). `mod` performs the modulo operation.
97+
98+Together, these operations will pull each digit out of `n` and put it into a
99+`list`. That's because dividing `n` by 10 will knock off one decimal place from
100+the value, and `mod` will store the actual discarded digit. To visualize this
101+complementarity, let's run some operations in the dojo:
102+
103+```
104+> (div 146 10)
105+14
106+
107+> (mod 146 10)
108+6
109+```
110+
111+* TODO What if we do this with vases? Can we accept a vase, map it to whatever
112+the correct value would be to extract each digit of the number in whatever base
113+we are interpreting it in?
114+
115+* TODO from Rob: we need a few exercises here. Maybe asking the reader to
116+make one that accepts a vase could be one?
learn/arvo/workbook/eightball.udonnew file+161
@@ -0,0 +1,161 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'4'
4+ title/'Magic 8-Ball'
5+ ==
6+;>
7+
8+# Magic 8-Ball
9+
10+In this lesson we'll write a generator that mimics the functionality of a
11+Magic 8-Ball, producing a randomized response with each run.
12+
13+Save the code below as `eightball.hoon` in your `/gen` directory.
14+
15+```
16+!:
17+:- %say
18+|= [[* eny=@uv *] *]
19+:- %noun
20+^- tape
21+=/ answers=(list tape)
22+ :~ "It is certain."
23+ "It is decidedly so."
24+ "Without a doubt."
25+ "Yes - definitely."
26+ "You may rely on it."
27+ "As I see it, yes."
28+ "Most likely."
29+ "Outlook good."
30+ "Yes."
31+ "Signs point to yes."
32+ "Reply hazy, try again"
33+ "Ask again later."
34+ "Better not tell you now."
35+ "Cannot predict now."
36+ "Concentrate and ask again."
37+ "Don't count on it."
38+ "My reply is no."
39+ "My sources say no."
40+ "Outlook not so good."
41+ "Very doubtful."
42+ ==
43+=/ rng ~(. og eny)
44+=/ val (rad:rng (lent answers))
45+(snag val answers)
46+```
47+
48+Let's go through our code in chunks so that we might more easily understand it.
49+
50+```
51+!:
52+```
53+
54+We start with the `!:` rune to enable a full stack trace for any errors. This
55+is good practice whenever developing something in Hoon.
56+
57+
58+```
59+:- %say
60+|= [[* eny=@uv *] *]
61+:- %noun
62+```
63+
64+To make our program produce a random result, we need entropy. To get entropy,
65+we need data from Arvo. To get data from Arvo, we use a generator of the
66+[`%say`](/docs/tutorials/generators) variety. The above code chunk is
67+the template that is followed for all `%say` generators.
68+
69+`:- %say` creates a cell with `%say` as that cell's head to define
70+the generator's format.
71+
72+`|= [[* eny=@uv *] *]` is the tail of the cell, a gate, and that gate's first
73+child, a sample. Because the only external data our program is interested in
74+using is entropy to seed our random-number generator, that's the only one we
75+will assign a face (`eny`). The `*` elements that you see represent any noun. We
76+use these as fillers: because we don't wish to use the data that's passed to
77+those parts of the sample, we don't assign them faces.
78+
79+`:- %noun` creates another cell, itself residing in the tail of our first cell
80+via our gate expression. In all `%say` generators, the head of this second cell
81+is a `mark` that's used to tell Arvo what kind of data the generator is
82+producing. In this case, we are using the `%noun` `mark` to tell the system how
83+to print the generator's outputted value. The tail of this cell is that value
84+itself, produced by the rest of our program.
85+
86+```
87+^- tape
88+```
89+
90+Above is a cast statement that requires the non-`mark` component of our cell to
91+be of the `tape` type. If it's not, the program doesn't compile.
92+
93+```
94+=/ answers=(list tape)
95+ :~ "It is certain."
96+ "It is decidedly so."
97+ "Without a doubt."
98+ "Yes - definitely."
99+ "You may rely on it."
100+ "As I see it, yes."
101+ "Most likely."
102+ "Outlook good."
103+ "Yes."
104+ "Signs point to yes."
105+ "Reply hazy, try again"
106+ "Ask again later."
107+ "Better not tell you now."
108+ "Cannot predict now."
109+ "Concentrate and ask again."
110+ "Don't count on it."
111+ "My reply is no."
112+ "My sources say no."
113+ "Outlook not so good."
114+ "Very doubtful."
115+ ==
116+```
117+
118+The code in the chunk above constructs the list of possible responses.
119+
120+`=/ answers=(list tape)` is used to put add data to the subject with a face,
121+so that we can easily use it later. The face is `answers`, and we designate that
122+its accompanying value will be a `list` of `tape`. The value itself is given
123+as a `list` in the lines that follow.
124+
125+`:~` is a rune that constructs a null-terminated list. Here we have used the
126+tall form for readability, as an alternative to the wide form of `~[1 2 3]` that
127+you may be more familiar with.
128+
129+Contained within the `:~` rune are the elements of the list. In our case, those
130+elements are the `tape`s that are selected as the 8-Ball's responses.
131+
132+`==` terminates our list. `:~` expressions are always closed in this way.
133+
134+```
135+=/ rng ~(. og eny)
136+=/ val (rad:rng (lent answers))
137+```
138+
139+The code above is our random-number engine.
140+
141+`og` is the core in the standard library that contains arms that perform
142+randomness-related operations. `=/ rng ~(. og eny)` passes `eny` to the
143+subject of `og`, and then stores the resulting core in a face called `rng`.
144+
145+`=/ val (rad:rng (lent answers))` uses `rad` arm. `rad` produces a random
146+number from `0` to `n-1`, where `n` the entropy-seeded `rng` core and pulls.
147+Is the upper bound that we give it. In this case, the upper bound is the number
148+of elements in `answers`, obtained by using the `lent` standard-library arm. We
149+store the random result in `val`.
150+
151+```
152+(snag val answers)
153+```
154+
155+`snag` is a standard-library arm that that takes two arguments: an atom and
156+a `list`. It fetches the element in position `n` of the list, where `n` is the
157+value of the atom it was passed. By using the randomized `val` as that position
158+argument, we can pull a different response from `answers` every time the
159+generator is run.
160+
161+TODO (rob): Exercises here.
learn/arvo/workbook/recursion.udonnew file+196
@@ -0,0 +1,196 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'2'
4+ title/'Recursion'
5+ ==
6+;>
7+
8+# Recursion
9+
10+Recursion is a common pattern for solving certain problems in many programming
11+languages, and Hoon is no exception. One of the classically recursive problems
12+is that of factorial. The factorial of _n_ is the product of all positive
13+integers less than or equal to N. Thus the factorial of 5, denoted as _5!_,
14+would be:
15+
16+```
17+5 * 4 * 3 * 2 * 1 = 120
18+```
19+
20+### Factorial In Hoon
21+
22+Let's implement a factorial calculator in Hoon. To do so, we'll write a
23+recursive `gate` (Hoon's equivalent of a function) to perform the relevant
24+computation. Save the code below as `factorial.hoon` in your ship's `/gen`
25+directory.
26+
27+```
28+|= n=@ud
29+?: =(n 1)
30+ 1
31+(mul n $(n (dec n)))
32+```
33+
34+Our `gate` takes one sample (argument) `n` that must nest inside `@ud`, the
35+unsigned-integer type.
36+
37+Next we check to see if `n` is `1`. If so, the result is just `1`, since
38+`1 * 1 = 1`.
39+
40+If, however, `n` is _not_ `1`, then we branch to the final line of the code,
41+`(mul n $(n (dec n)))`, where the recursion logic lives. Here, we multiply `n`
42+by the recursion of `n` minus `1`. `$` initiates recursion: it calls the gate
43+that we're already in, but replaces its sample.
44+
45+In our example, we multiply `n` with the product of this _entire gate
46+all over again_ with `$(n (dec n))`, except when that new gate has its sample
47+decremented by one. This works recursively because each new gate will, of
48+course, itself contain the code to call a further-decremented gate. Gates will
49+continue to call new, further-decremented gates until `n` is `1`, and that `1`
50+will be the final number to be multiplied by.
51+
52+Let's run the program in the Dojo:
53+
54+```
55+> +factorial 5
56+120
57+```
58+
59+It may help to visualize the operation our example gate. The pseudo-Hoon below
60+illustrates what happens when we use it to find the factorial of 5:
61+
62+```
63+(factorial 5)
64+(mul 5 (factorial 4))
65+(mul 5 (mul 4 (factorial 3)))
66+(mul 5 (mul 4 (mul 3 (factorial 2))))
67+(mul 5 (mul 4 (mul 3 (mul 2 (factorial 1)))))
68+(mul 5 (mul 4 (mul 3 (mul 2 1))))
69+(mul 5 (mul 4 (mul 3 2)))
70+(mul 5 (mul 4 6))
71+(mul 5 24)
72+120
73+```
74+
75+It's easy to see how we're "floating" gate calls until we reach the final
76+iteration of such calls that only produces a value. The `mul n` component of the
77+gate leaves something like `mul 5`, waiting for the a final series of terms
78+to be operated upon. The `$(n (dec n))` component is what expands out the
79+expression, as illustrated by `(factorial 4)`. Once the expression cannot be
80+expanded out further, the operations work backwards, successively feeding values
81+into the `mul` functions behind them.
82+
83+##### Tail-Call Optimization
84+
85+Our last example isn't a very efficient use computing resources. The
86+pyramid-shaped illustration approximates what's happening on the *call stack*, a
87+memory structure that tracks the instructions of the program. In our example
88+code, every time a parent gate calls another gate, the gate being called is
89+"pushed" to the top of the stack in the form of a frame. This process continues
90+until a value is produced instead of a function, completing the stack.
91+
92+```
93+ Push order Pop order
94+(fifth frame) ^ |
95+(fourth frame) | |
96+(third frame) | |
97+(second frame) | |
98+(first frame) | V
99+```
100+
101+Once this stack of frames is completed, frames "pop" off the stack starting at
102+the top. When a frame is popped, it executes the contained gate and passes
103+produced data to the frame below it. This process continues until the stack
104+is empty, giving us the gate's output.
105+
106+When a program's final expression uses the stack in this way, it's considered to
107+be *not tail-recursive*. This usually happens when the last line of executable
108+code calls more than one gate, our example code's `(mul n $(n (dec n)))` being
109+such a case. That's because such an expression needs to hold each iteration of
110+`$(n (dec n)` in memory so that it can know what to run against the `mul`
111+function every time.
112+
113+To reiterate: if you have to manipulate the result of a recursion as the last
114+expression of your gate, as we did in our example, the function is not
115+tail-recursive, and therefore not very efficient with memory. A problem arises
116+when we try to recurse more times that we have space on the stack. This will
117+result in our computation failing and producing a stack overflow. If we tried
118+to find the factorial of `5.000.000`, for example, we would almost certainly
119+run out of stack space.
120+
121+But the Hoon compiler, like most compilers, is smart enough to notice when the
122+last statement of a parent can reuse the same frame instead of needing to
123+add new ones onto the stack. If we write our code properly, we can use a single
124+frame that simply has its values replaced with each recursion.
125+
126+##### A Tail-Recursive Gate
127+
128+With a bit of refactoring, we can write a version of our factorial gate that
129+_is_ tail-recursive and can take advantage of this feature:
130+
131+```
132+|= n=@ud
133+=/ t=@ud 1
134+|-
135+?: =(n 1)
136+ t
137+$(n (dec n), t (mul t n))
138+```
139+
140+The above code should look familiar. We are still building a gate that
141+takes one argument `n`. This time, however, we are also putting a face on a
142+`@ud` and setting it's initial value to 1. The `|-` here is used to create a new
143+gate with one arm `$` and immediately call it. Think of `|-` as the recursion
144+point.
145+
146+We then evaluate `n` to see if it is 1. If it is we return the value of `t`. In
147+the case that `n` is anything other than 1, we perform our recursion:
148+
149+```
150+$(n (dec n), t (mul t n))
151+```
152+
153+All we are doing here is recursing our new gate and modifying the values of `n`
154+and `t`. `t` is used as an accumulator variable that we use to keep a running
155+total for the factorial computation.
156+
157+Let's use pseudo-Hoon to illustrate how the stack is working in this example for
158+factorial 5.
159+
160+```
161+(factorial 5)
162+(|- 5 1)
163+(|- 4 5)
164+(|- 3 20)
165+(|- 2 60)
166+(|- 1 120)
167+120
168+```
169+
170+We simply multiply `t` and `n` to produce the new value of `t`, and then
171+decrement `n` before repeating. Since this `$` call is the final and solitary
172+thing that is run in the default case and since we are doing all computation
173+before the call, this version is properly tail-recursive. We don't need to do
174+anything to the result of the recursion except recurse it again. That means that
175+each iteration can be replaced instead of held in memory.
176+
177+##### A Note on `$`
178+
179+`$` is, in its use with recursion, a reference to the gate that we are inside
180+of. That's because a gate is just a core with a single arm named `$`. The
181+subject is searched depth-first, head before tail, with faces skipped, and
182+stopping on the first result. In other words, the first match found in the head
183+will be returned. If you wished to refer to the outer `$` in this context, the
184+idiomatic way would be to use [`^$`](/docs/reference/rune/ket). The `^` operator
185+skips the first match of a name.
186+
187+### Exercises
188+
189+1. Write a recursive gate that produces the first _n_
190+[Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number)
191+
192+2. Write a recursive gate that produces a list of moves to solve the
193+[Tower of Hanoi problem](https://en.wikipedia.org/wiki/Tower_of_Hanoi).
194+Disks are stacked on a pole by decreasing order of size. Move all of the
195+disks from one pole to another with a third pole as a spare, moving one
196+disc at a time, without putting a larger disk on top of a smaller disk.
learn/arvo/workbook/traffic-light.udonnew file+158
@@ -0,0 +1,158 @@
1+:- :~ navhome/'/docs/'
2+ next/'true'
3+ sort/'5'
4+ title/'Traffic Light'
5+ ==
6+;>
7+
8+# Traffic Light
9+
10+Let's create a state machine in Hoon that models the functionality of a traffic
11+light. Save the code below as `traffic.hoon` in your `/gen` directory.
12+
13+```
14+:- %say
15+|= *
16+:- %noun
17+=+ |%
18+ ++ state ?(%red %yellow %green)
19+ --
20+=/ current-state=state %red
21+=+ ^= traffic-light
22+ |%
23+ ++ look current-state
24+ ++ set
25+ |= s=state
26+ +>.$(current-state s)
27+ --
28+=+ a=traffic-light
29+=+ b=traffic-light
30+=. a (set.a %yellow)
31+[current-state.a current-state.b]
32+```
33+
34+Let's look at the code piece-by-piece.
35+
36+```
37+:- %say
38+|= *
39+:- %noun
40+```
41+
42+Here's the boilerplate code to designate our generator as being a
43+[`%say` generator](/docs/tutorials/generators). We're using this variant because
44+it allows us to run the generator without any arguments. It's otherwise not
45+relevant to the functionality of our program.
46+
47+```
48+=+ |%
49+ ++ state ?(%red %yellow %green)
50+ --
51+```
52+
53+`=+` adds a noun to the subject. In our case, the noun in question is the core
54+that is opened with `|%` and closed with `--`. This core is used to store types,
55+and does that with the arm that it contains.
56+
57+`++ state` creates an arm called `state`, which will be used as the name of the
58+new type that is created in the code that follows, `?(%red %yellow %green)`.
59+That following code creates a new type from the union of its elements. In this
60+case, the state can be one of three values: `%red`, `%yellow`, or `%green`
61+corresponding to the three colors of a standard traffic light.
62+
63+Having new types in a separate core is a common idiom in Hoon programs that allows
64+the compiler to do [constant folding](https://en.wikipedia.org/wiki/Constant_folding),
65+which improves performance.
66+
67+```
68+=/ current-state=state %red
69+```
70+
71+The line above creates a noun of type `state` - the type that we created with
72+the arm in previous code chunk - and gives it a default value. Because we are
73+putting this noun into the subject, it will be available for use in the
74+`traffic-light` core we are about to create.
75+
76+```
77+=+ ^= traffic-light
78+ |%
79+ ++ look current-state
80+ ++ set
81+ |= s=state
82+ +>.$(current-state s)
83+ --
84+```
85+
86+`=+ ^= traffic-light` does two things. The `^=` rune assigns a face to that
87+noun so it's easier to reference. The `=+` rune adds a noun to the subject, in
88+this case the core that we just assigned a name and start to build on the next
89+line and assigned the name.
90+
91+With `|%`, we are finally at the meat of the program. This core that we just
92+named has two arms: `look`, which gives us the current state, defined later; and
93+`set`, which gives us a simple way to modify the value of `current-state`.
94+
95+The gate we are producing with `|=` may look a bit strange, so let's break it
96+down.
97+
98+`s=state` allows for an argument of type `state` and gives it a face `s`.
99+
100+We first produce a core with one arm named `$`. That `$` arm will produce a new
101+core with `current-state` changed to match the `s` provided when it was called.
102+How does this work?
103+
104+Remember that `.` is [wing syntax](/docs/tutorials/hoon-ch1/hoon-ch1-4) that
105+applies the wing expression on the left of it to the noun to the right of it.
106+`$` is the arm of the core. Then by using the wing expression `+>`, which means
107+"return the head of the tail", we traverse the subject to the core to latch onto
108+its parent core. where we defined the arms `look` and `set`. The `( )` then
109+lists changes to the core we would like to make as we produce a new one. You
110+will often see `+>.$` used in this way.
111+
112+```
113+=+ a=traffic-light
114+=+ b=traffic-light
115+```
116+
117+Now we have the last parts of our program. Remember that `=+` allows us to add a
118+noun to the head of the subject. In this case, we are adding two nouns, one with
119+the face `a` and a second with the face `b`. These two nouns will be copies of
120+the `traffic-light` core, with all the bits we previously created.
121+
122+```
123+=. a (set.a %yellow)
124+```
125+
126+`=.` changes a leg in the subject. We use the `set` arm on `a` to produce a gate
127+and give that the argument of `%yellow`. Remember that we are actually producing
128+a new core in the gate, so we have to then assign that back to the face `a`.
129+
130+```
131+[current-state.a current-state.b]
132+```
133+
134+Here we simply are creating a new cell that has the `current-state` from `a` as
135+it's head and the `current-state` from `b` as it's tail.
136+
137+Let's run it in the Dojo to get our product:
138+
139+```
140+> +traffic
141+[%yellow %red]
142+```
143+
144+### Exercises
145+
146+1. Modify the generator to include a way to cycle the light without
147+explicitly having to select the next color. That is, if the light is currently
148+`%green` then the next color would be `%yellow`. If `%yellow` then the next
149+color should be `%red`.
150+
151+2. Using what you have learned about creating state machines in Hoon,
152+produce a state machine that can act as a vending-machine emulator. It should
153+keep track of the amount of items it has, as well as the amount of money that an
154+item costs. To keep it simple, assume this vending machine only has one item for
155+sale.
156+
157+3. Modify your vending machine from exercise 2 to support holding multiple items
158+with different prices.