on master help sign in
Merge pull request #210 from mattlevan/arvo
fc698e8Keaton Dunsford
docs/arvo/basic.md+89−68
@@ -14,32 +14,68 @@ fundamentals of [Hoon](/docs/hoon/). To do this, we'll walk through two simple
14programs: the first [Project Euler](https://projecteuler.net/) problem
14programs: the first [Project Euler](https://projecteuler.net/) problem
15and [fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
15and [fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
16
16
17−To run this code, you'll need an urbit, and will have to copy the
17+To run this code, you'll need an urbit, and will have to either sync or copy the
18[examples repo](https://github.com/urbit/examples) into it.
18[examples repo](https://github.com/urbit/examples) into it.
19
19
20−If you haven't installed urbit yet, check out the [installation
20+## Installation
21−instructions](/docs/using/install). Once urbit is installed, take a look
22−at the [basic operation](/docs/using/admin) of your urbit.
23
21
24−If you haven't copied in the examples repo, running the following
22+First, you'll need a running urbit. Follow our urbit.org [install
25−commands from your urbit directory should do the trick:
23+instructions](https://urbit.org/docs/using/install), then
24+[setup](https://urbit.org/docs/using/setup) and urbit.
26
25
27−Make sure you've mounted your `%home` desk:
26+Follow the *Network install* below if your urbit is running on the live network
27+(comets are usually best for development). Follow the *Local install* instead
28+if you're on a
29+[fake ship](https://urbit.org/fora/posts/~2017.1.5..21.31.04..20f3~/) or are
30+otherwise experiencing problems with the network install.
28
31
29−```
32+### Network install
30−~fintud-macrep:dojo> |mount %
31−```
32
33
33−Then, copy the example into it
34+In your urbit's `:dojo`, run the command:
34
35
35−```
36+ ~your-urbit:dojo> |sync %examples ~ropmev-pocseb %examples
36−$ cp -r {urbit-examples}/gall/*/* {your-pier}/home/
37+
37−$ cp -r {urbit-examples}/dojo/*/* {your-pier}/home/
38+Depending on network traffic, this initial merge and sync could take anywhere
38−```
39+between thirty seconds to several minutes. Upon a successful sync you'll see the
40+output:
41+
42+ sync succeeded from %examples on ~ropmev-pocseb to %examples
43+
44+In which case, next run the commands:
45+
46+ ~your-urbit:dojo> =dir /=examples=
47+ ~your-urbit:dojo/examples> |serve %/web
48+ ~your-urbit:dojo/examples> |mount %
49+
50+If your sync isn't succeeding after a few minutes for whatever reason, run
51+`|cancel %examples` in your `:dojo` and follow the local install below instead.
52+
53+### Local install
54+
55+In your urbit's `:dojo`:
56+
57+ ~your-urbit:dojo> |merge %examples our %base, =gem %init
58+ ~your-urbit:dojo> =dir /=examples=
59+ ~your-urbit:dojo/examples> |serve %/web
60+ ~your-urbit:dojo/examples> |mount %
61+
62+If `~your-urbit` was installed at `/urbit/path` on your Unix machine, you can
63+now find your `%examples` desk at the path `/urbit/path/your-urbit/examples`.
64+
65+Lastly, in Unix, clone this repo somewhere and copy in the `examples` files to
66+your urbit's new mounted `%examples` desk. You can run the following shell
67+commands (*replacing your urbit's examples desk path as necessary*):
68+
69+ $ git clone https://github.com/urbit/examples
70+ $ for dir in {app,gen,lib,mar,sec,sur,web}; do cp -r ./examples/$dir* /urbit/path/your-urbit/examples; done
71+
72+Your `%clay` filesystem should acknowledge the newly added files.
73+
74+## Get started!
39
75
40Run an example to ensure it worked:
76Run an example to ensure it worked:
41
77
42− ~fintud-macrep:dojo> +examples-euler1
78+ ~fintud-macrep:dojo> +project-euler/p1
43 233.168
79 233.168
44
80
45Euler 1
81Euler 1
@@ -53,42 +89,44 @@ Let's check out the code for Euler 1. First, the problem:
53 Find the sum of all the multiples of 3 or 5 below 1000.
89 Find the sum of all the multiples of 3 or 5 below 1000.
54
90
55Here is the hoon solution (which should be in your pier directory under
91Here is the hoon solution (which should be in your pier directory under
56−`/gen/examples/euler1`):
92+`/examples/gen/project-euler/p1`):
57
93
58− :: project euler 1
94+ :: Project Euler 1
59− :: https://projecteuler.net/problem=1
95+ :: https://projecteuler.net/problem=1
60− :: run in dojo with +examples-euler1
61 ::
96 ::
62− :::: /hoon/euler1/examples/gen
97+ :: run in dojo with:
98+ :: ~your-urbit:dojo/examples> +project-euler/p1
99+ ::
100+ :::: /===/gen/project-euler/p1/hoon
63− ::
101+ ::
102+ !:
103+ ::
64− :- %say |= *
104+ :- %say |= *
65 :- %noun
105 :- %noun
66 =< (sum 1.000)
106 =< (sum 1.000)
67 ::
107 ::
68− :::: ~sivtyv-barnel
69− ::
70 |%
108 |%
71 ++ three
109 ++ three
72− |= a/@
110+ |= a/@
73− =| b/@
111+ =| b/@
74− |- ^- @u
112+ |- ^- @u
75 ?: (lth a b)
113 ?: (lth a b)
76− 0
114+ 0
77 (add b $(b (add 3 b)))
115 (add b $(b (add 3 b)))
78 ::
116 ::
79 ++ five
117 ++ five
80− |= a/@
118+ |= a/@
81− =| b/@
119+ =| b/@
82 |- ^- @
120 |- ^- @
83 ?: (lte a b)
121 ?: (lte a b)
84− 0
122+ 0
85 ?: =((mod b 3) 0)
123 ?: =((mod b 3) 0)
86− $(b (add b 5))
124+ $(b (add b 5))
87 (add b $(b (add b 5)))
125 (add b $(b (add b 5)))
88 ::
126 ::
89− ++ sum
127+ ++ sum
90 |= a/@u
128 |= a/@u
91− (add (five a) (three a))
129+ (add (five a) (three a))
92 --
130 --
93
131
94> Hoon is not generally whitespace sensitive, but we do have two
132> Hoon is not generally whitespace sensitive, but we do have two
@@ -97,7 +135,7 @@ Here is the hoon solution (which should be in your pier directory under
97> Really. For a more detailed explanation of when to use spaces vs.
135> Really. For a more detailed explanation of when to use spaces vs.
98> gaps, see the syntax section before the first exercises.
136> gaps, see the syntax section before the first exercises.
99
137
100−### Lines 1-11:
138+### Lines 1-13:
101
139
102Any line that begins with `::` is a comment.
140Any line that begins with `::` is a comment.
103
141
@@ -117,8 +155,8 @@ rune takes a specific number of children, either expressions formed by
117other runes or literals that produce their own value (some runes take
155other runes or literals that produce their own value (some runes take
118*N* children, and are usually closed with `==`).
156*N* children, and are usually closed with `==`).
119
157
120−For example, the rune `?:` from line 18 is the classic 'if-then-else'
158+For example, the rune `?:` from line 20 is the classic 'if-then-else' statement,
121−statement, and thus takes three children:
159+and thus takes three children:
122
160
123 ?: (lth a b) :: if first child evals to true
161 ?: (lth a b) :: if first child evals to true
124 0 :: then produce result of second
162 0 :: then produce result of second
@@ -149,32 +187,15 @@ See the entire naming scheme below.
149
187
150Using this scheme, we would pronounce `?:` as 'wutcol'.
188Using this scheme, we would pronounce `?:` as 'wutcol'.
151
189
152−For those who prefer to use reserved words to form expressions, you can
190+### Lines 14-37
153−substitute any rune with that rune's keyword, which you can find in
154−`++twig` in `/arvo/hoon.hoon`. For example, here's the code for `?:` in
155−`++twig`:
156
191
157−`{$if p/twig q/twig r/twig} :: ?: if/then/else`
158−
159−Instead of:
160−
161− ?:(=(1 2) 'this is true' 'this is false')
162− 'this is false'`
163−
164−You can write:
165−
166− :if(=(1 2) 'this is true' 'this is false')
167− 'this is false'
168−
169−### Lines 13-35
170−
171−Now let's quickly walk through this code line-by-line. Lines 13-35 are
192+Now let's quickly walk through this code line-by-line. Lines 14-37 are wrapped
172−wrapped in a `|%` ('[barcen](../../hoon/twig/bar-core/cen-core/)'), which produces a core. Cores are a
193+in a `|%` ('[barcen](../../hoon/twig/bar-core/cen-core/)'), which produces a
173−fundamental datatype in Hoon, similar to a struct, class, or object. A
194+core. Cores are a fundamental datatype in Hoon, similar to a struct, class, or
174−core is just a map of names to any kind of code, whether it be functions
195+object. A core is just a map of names to any kind of code, whether it be
175−or data. Each element in this map begins with a `++` followed by the
196+functions or data. Each element, called an arm, in this map begins with a `++`
176−name and the corresponding code. Since `|%` takes an arbitrary number of
197+followed by the name and the corresponding code. Since `|%` takes an arbitrary
177−children, it needs to be closed with a `--`.
198+number of children, it needs to be closed with a `--`.
178
199
179> `++` ('luslus') is not technically a rune, since it is only used in
200> `++` ('luslus') is not technically a rune, since it is only used in
180> core syntax, as shown above.
201> core syntax, as shown above.
@@ -184,7 +205,7 @@ Let's step into each of the three arms within our core.
184### `++ sum`
205### `++ sum`
185
206
186 ++ sum
207 ++ sum
187− |= a/@
208+ |= a/@u
188 (add (five a) (three a))
209 (add (five a) (three a))
189 --
210 --
190
211
@@ -195,10 +216,10 @@ takes two children:
195 one: `a`, which is required to be an atom or natural number, denoted
216 one: `a`, which is required to be an atom or natural number, denoted
196 by `@`.
217 by `@`.
197
218
198−2. The body of the function itself, which is executed when the function
219+2. The body of the function itself, which is executed when the function is
199− is called (in this case, with `(sum 1.000)`). This particular
220+ called (in this case, with `(sum 1.000)`). This particular function adds the
200− function adds the results of evaluating the gates `++ five` and
221+ results of evaluating the gates `++five` and `++three` with each of their
201− `++three` with each of their respective input parameters set to `a`.
222+ respective input parameters set to `a`.
202
223
203### ++ three
224### ++ three
204
225
docs/arvo/network.md+173−157
@@ -11,70 +11,73 @@ Network messages
11Now we've learned enough Hoon to do more interesting things. Let's get
11Now we've learned enough Hoon to do more interesting things. Let's get
12our planets to talk to each other.
12our planets to talk to each other.
13
13
14−All we've written up until now are just shell commands that produce a
14+All we've written up until now are just shell commands that produce a value and
15−value and then disappear. To listen for and receive messages from other
15+then disappear. To listen for and receive messages from other planets, we'll
16−planets, we'll need an app. Let's look at a very simple one:
16+need an app. Let's look at a very simple one, `echo.hoon`:
17
17
18 :: Accepts any noun from dojo and prints it out
18 :: Accepts any noun from dojo and prints it out
19 ::
19 ::
20− :::: /hoon/echo/examples/app
20+ :::: /===/app/echo/hoon
21 ::
21 ::
22− /? 314
22+ !: :: enables debug printfs
23− !:
23+ |% :: forms a core with subject as payload
24− |_ {bowl state/$~}
24+ ++ move {bone card} :: defines echo app's arvo move mold
25− ++ poke-noun
25+ ++ card $% $~ :: defines card (data) mold as null tagged union
26− |= arg/*
26+ == :: end of mold definition; see $%
27− ^- {(list) _+>.$}
27+ -- :: end of card arm definition
28− ~& [%argument arg]
28+ :: ::
29− [~ +>.$]
29+ |_ {bow/bowl $~} :: forms a core with bowl (app state) as sample
30− --
30+ ++ poke-noun :: begin definition of poke-noun arm
31+ |= non/* :: forms a gate which accepts any noun
32+ ^- {(list move) _+>.$} :: casts product to mold of moves and context
33+ ~& echo+noun+non :: debug printf, i.e. '[%echo %noun *]'
34+ [~ +>.$] :: produce a cell of empty list and our state
35+ -- :: end of poke-noun arm definition
31
36
32This is a very simple app that does only one thing. If you poke it with
37This is a very simple app that does only one thing. If you poke it with
33a value, it prints that value out. To try this out, you have to start
38a value, it prints that value out. To try this out, you have to start
34the app, then you can poke it from the command line with the following
39the app, then you can poke it from the command line with the following
35commands:
40commands:
36
41
37− ~fintud-macrep:dojo> |start %examples-echo
42+ ~fintud-macrep:dojo> |start %echo
38− 'prep'
39 >=
43 >=
40− ~fintud-macrep:dojo> :examples-echo 5
44+ ~fintud-macrep:dojo> :echo 5
41− [%argument 5]
45+ [%echo %noun 5]
42 >=
46 >=
43 ~fintud-macrep:dojo> :examples-echo [1 2]
47 ~fintud-macrep:dojo> :examples-echo [1 2]
44− [%argument [1 2]]
48+ [%echo %noun [1 2]]
45 >=
49 >=
46
50
47−> There is currently a bug where the `%argument` lines are printed
51+> There is currently a bug where the `[%echo %noun *]` lines are printed *above*
48−> *above* the line you entered, so your output may not look exactly like
52+> the line you entered, so your output may not look exactly like this. `>=`
49−> this. `>=` means that a command was successfully received and
53+> means that a command was successfully received and executed.
50−> executed.
51
54
52Most of the app code should be simple enough to guess its function. The
55Most of the app code should be simple enough to guess its function. The
53important part of this code is the definition of `++poke-noun`.
56important part of this code is the definition of `++poke-noun`.
54
57
55−Once an app starts, it's always running in the background and you
58+Once an app starts, it's always running in the background and you interact with
56−interact with it by sending it messages. The most straightforward way to
59+it by sending it messages. The most straightforward way to do that is to poke it
57−do that is to poke it from the command line, which we we did with
60+from the command line, which we we did with `:echo 5`
58−`:echo 5` (`:[app-name] [argument(s)]`).
61+(`:[app-name] [argument(s)]`).
59
62
60−In this case, `++poke-noun` takes an argument `arg` and prints it out
63+In this case, `++poke-noun` takes an argument (*sample*) `arg` and
61−with `~&` ([sigpam](../../hoon/twig/sig-hint/pam-dump/)). This is an unusual
64+prints it to dojo with `~&` ([sigpam](../../hoon/twig/sig-hint/pam-dump/)).
62−rune that formally "does nothing", but the interpreter detects it and
65+This is an unusual rune that formally "does nothing", but the interpreter
63−printfs the first child, before executing the second as if the first
66+detects it and printfs the first child, before executing the second as if the
64−didn't exist. This is a slightly hacky way of printing to the console,
67+first didn't exist. This is a slightly hacky way of printing to the console,
65but we'll get to the correct way later on.
68but we'll get to the correct way later on.
66
69
67−But what does `++poke-noun` produce? Recall that `^-` casts to a type.
70+But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
68−In this case, it's declaring that the end result of the function will be of
71+case, it's declaring that the end result (*product*) of the function
69−type `{(list) _+>.$}`. But what does this mean?
72+(`++poke-noun`'s *gate*) will be of type `{(list) _+>.$}`. But what does this
73+mean?
70
74
71−The phrase to remember is "a list of moves and our state". Urbit is a
75+The phrase to remember is "a list of moves and our state". Urbit is a message
72−message passing system, so whenever we want to do something that
76+passing system, so whenever we want to do something that interacts with the rest
73−interacts with the rest of the system, we send a message. Thus, a move
77+of the system, we send a message. Thus, a move is Arvo's equivalent of a
74−is Arvo's equivalent of a syscall. The first thing that `++poke-noun`
78+syscall. The first thing that `++poke-noun` produces is a list of messages,
75−produces is a list of messages, called "moves". In this case, we don't
76−actually want the system to do anything, so we produce the empty list,
79+called "moves". In this case, we don't actually want the system to do anything,
77−`~` (in the `[~ +>.$]` line).
80+so we produce the empty list, `~` (in the `[~ +>.$]` line).
78
81
79The second thing `++poke-noun` produces is our state. `+>.$` refers to a
82The second thing `++poke-noun` produces is our state. `+>.$` refers to a
80particular address in our subject where our formal app state is stored.
83particular address in our subject where our formal app state is stored.
@@ -85,21 +88,28 @@ Let's look at another example (edit your code in
85`/app/examples/echo/hoon` to reflect the code below). Say we want to
88`/app/examples/echo/hoon` to reflect the code below). Say we want to
86only accept a number, and then print out the square of that number.
89only accept a number, and then print out the square of that number.
87
90
88− /? 314
91+ :: Accepts an atom from the dojo and squares it.
89− !:
90− |_ {bowl state/$~}
91 ::
92 ::
93+ :::: /===/app/square/hoon
94+ ::
95+ !:
96+ |% ::> no moves in :square
97+ ++ move {bone card} ::> no cards in :square
98+ ++ card $% $~
99+ ==
100+ --
101+ :: ::< stateless
102+ |_ {bow/bowl $~}
92 ++ poke-atom
103 ++ poke-atom
93− |= arg/@
104+ |= tom/@
94− ^- {(list) _+>.$}
105+ ^- {(list move) _+>.$}
95− ~& [%square (mul arg arg)]
106+ ~& square+(mul tom tom)
96− [~ +>.$]
107+ [~ +>.$]
97− --
108+ --
98
109
99−A few things have changed. Firstly, we no longer accept arbitrary nouns
110+A few things have changed. Firstly, we no longer accept arbitrary nouns because
100−because we can only square atoms (integers, in this case an unsigned
111+we can only square atoms (integers, in this case an unsigned one). Thus, our
101−one). Thus, our argument is now `arg/@`. Secondly, it's `++poke-atom`
112+argument is now `tom/@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
102−rather than `++poke-noun`.
103
113
104Intro to marks
114Intro to marks
105==============
115==============
@@ -124,9 +134,9 @@ using `&[mark]`. Try the following commands:
124
134
125 ~fintud-macrep:dojo> |start %square
135 ~fintud-macrep:dojo> |start %square
126 >=
136 >=
127− ~fintud-macrep:dojo> :examples-square 6
137+ ~fintud-macrep:dojo> :square 6
128 gall: %square: no poke arm for noun
138 gall: %square: no poke arm for noun
129− ~fintud-macrep:dojo> :examples-square &atom 6
139+ ~fintud-macrep:dojo> :square &atom 6
130 [%square 36]
140 [%square 36]
131 >=
141 >=
132
142
@@ -143,68 +153,79 @@ so we'll be getting quite used to them.
143Sending a message to another urbit
153Sending a message to another urbit
144==================================
154==================================
145
155
146−Let's write our first network message! Here's `/app/examples/pong.hoon`:
156+Let's write our first network message! Here's `examples/app/pong.hoon`:
147
157
148− /? 314
158+ :: Allows one urbit to send the string 'Pong' to
159+ :: another urbit.
160+ ::
161+ :::: /===/app/pong/hoon
162+ ::
163+ !:
149 |%
164 |%
150− ++ move {bone term wire *}
165+ ++ move {bone card}
166+ ++ card $% {$poke wire dock poke-contents}
167+ ==
168+ ++ poke-contents $% {$atom @}
169+ ==
151 --
170 --
152− !:
171+ |_ {bow/bowl $~} ::< stateless
153− |_ {bowl state/$~}
154 ::
172 ::
155 ++ poke-urbit
173 ++ poke-urbit
156− |= to/@p
174+ |= to/ship
157 ^- {(list move) _+>.$}
175 ^- {(list move) _+>.$}
176+ ~& pong+'Outgoing pong!'
177+ :_ +>.$
158− [[[ost %poke /sending [to dap] %atom 'howdy'] ~] +>.$]
178+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
159 ::
179 ::
160 ++ poke-atom
180 ++ poke-atom
161− |= arg/@
181+ |= tom/@
162 ^- {(list move) _+>.$}
182 ^- {(list move) _+>.$}
163− ~& [%receiving (@t arg)]
183+ ~& pong+'Incoming pong!'
184+ ~& pong+received+`@t`tom
164 [~ +>.$]
185 [~ +>.$]
165 ::
186 ::
166 ++ coup |=(* [~ +>.$])
187 ++ coup |=(* [~ +>.$])
188+ ::
167 --
189 --
168−
190+
169Run it with these commands:
191Run it with these commands:
170
192
171− ~fintud-macrep:dojo> |start %examples-pong
193+ ~fintud-macrep:dojo> |start %pong
172 >=
194 >=
173− ~fintud-macrep:dojo> :examples-pong &urbit ~sampel-sipnym
195+ ~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
174 >=
196 >=
175
197
176−Replace `~sampel-sipnym` with another urbit. The easiest thing to do is
198+Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
177−to start a comet, a free and disposable Urbit identity. If you don't know
199+a comet, a free and disposable Urbit identity. If you don't know how to start a
178−how to start a comet, see [the user setup section](/docs/using/setup/).
200+comet, see [the user setup section](/docs/using/setup/). Don't forget to start
179−Don't forget to start the `%examples-pong` app on that urbit, too. You
201+the `%pong` app on that urbit, too. You should see, on the foreign
180−should see, on the foreign urbit, this output:
202+urbit, this output:
181−
203+
182− [%receiving 'howdy']
204+ [%pong 'Incoming pong!']
183−
205+ [%pong %received 'Pong']
206+
184−Most of the code should be straightforward. In `++poke-atom`, the only
207+Most of the code should be straightforward. In `++poke-atom`, the only new thing
185−new thing is the expression `(@t arg)`, which is the type `@t` being
208+is the expression `` `@t`tom ``, which is *casting* the argument `tom` to type
186−called as a function with argument `arg`. As we already know, `@t` is
187−the type of "cord" text strings. In Hoon, when types are called as
209+`@t`. As we already know, `@t` is the type of "cord" (text string). In Hoon,
210+another way to perform a kind of casting is to use a type as a function, like
211+this: `(@t tom)`. When types are called like this, they are called "clams",
188−functions, they serve as a validator function called a "clam" -- that
212+and they serve as validator functions-- that is, functions whose domain is all
189−is, a function whose domain is all nouns, and range is the given type
213+nouns, and range is the given type (in this case, `@t`). Clams will "bunt" the
190−(in this case, `@t`).
214+default value of the mold whereas casts (`@t`tom) may `nest-fail` if the
191−
215+argument passed to it does not fit. An example of such a failure case is
192−In simpler terms, if a clam is passed a value of its own type, it
216+passing a cell to an atom: `` `@`[1 2] ``. Using a clam here instead
193−produces that value. Otherwise, it produces the default value (aka the
217+(`(@ [1 2])`) will bunt the default value of `@`, which is `0`. Try it in dojo!
194−"bunt") of its type. Here we call this `@t` function on the argument.
218+
195−This coerces the argument to text, so that we can print it out prettily
196−no matter what we're passed.
197−
198−The more interesting part is in `++poke-urbit`. The `urbit` mark is an
219+The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
199−urbit identity, and the Hoon type associated with it is `@p` (the "p"
220+identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
200stands for "phonetic base").
221stands for "phonetic base").
201
222
202−Recall that in a `++poke` arm we produce "a list of moves and our
223+Recall that in a `++poke` arm we produce "a list of moves and our state". Until
203−state". Until now, we've left the list of moves empty, since we haven't
224+now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
204−wanted to tell Arvo to do anything in particular. Now we want to send a
225+do anything in particular. Now we want to send a message to another urbit. Thus,
205−message to another urbit. Thus, we produce a list with one element:
226+we produce a list with one element:
206
227
207− [ost %poke /sending [to-urbit-address %pong] %atom 'howdy']
228+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
208
229
209### Moves
230### Moves
210
231
@@ -218,73 +239,68 @@ Let's walk through each of these elements step by step.
218
239
219#### Bones ("cause")
240#### Bones ("cause")
220
241
221−If you look up `++bone` in `hoon.hoon`, you'll see that it's a number
242+If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
222−(`@ud`), and that it's an opaque reference to a duct. `++duct` in
243+and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
223−hoon.hoon is a list of `wire`s, where `++wire` is an alias for `++path`.
244+of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
224−`++path` is a list of `++knot`s, which are ASCII text. Thus, a duct is a
245+`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
225−list of paths, and a bone is an opaque reference to it (in the same way
246+an opaque reference to it (in the same way that a Unix file descriptor is an
226−that a Unix file descriptor is an opaque reference to a file structure).
227−Thus, to truly understand bones, we must understand ducts.
247+opaque reference to a file structure). Thus, to truly understand bones, we must
228−
248+understand ducts.
249+
229−A duct is stack of causes, again, represented as paths, which are called
250+A duct is a stack of causes, again, represented as paths, which are called wires.
230−wires. At the bottom of every duct is a unix event, such as a keystroke,
251+At the bottom of every duct is a unix event, such as a keystroke, network
231−network packet, file change, or timer event. When Arvo is given this
252+packet, file change, or timer event. When Arvo is given this event, it routes
232−event, it routes the event to appropriate kernel module for handling.
253+the event to appropriate kernel module for handling.
233−
254+
234−Sometimes, the module can immediately handle the event and produce any
255+Sometimes, the module can immediately handle the event and produce any necessary
235−necessary results. For example, when we poked the `++poke-atom` arm
256+results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
236−above, we poked %gall, our application server, which was able to respond
257+our application server, which was able to respond to our poke directly. When the
237−to our poke directly. When the module cannot service the request itself,
258+module cannot service the request itself, it sends instructions to another
238−it sends instructions to another kernel module or application (through the
259+kernel module or application (through the %gall module) to do a specified
239−%gall module) to do a specified action, and produces the result from
260+action, and produces the result from that.
240−that.
241
261
242Furthermore, when one module sends a message to another kernel module or
262Furthermore, when one module sends a message to another kernel module or
243−application, it also sends along the duct it was given with its new wire
263+application, it also sends along the duct it was given with its new wire tacked
244−tacked onto the end. Now the duct has two entries, with the unix event on
264+onto the top. Now the duct has two entries, with the unix event on the bottom
245−the bottom and the kernel module that handled it next. This process can
265+and the kernel module that handled it on top. This process can continue
246−continue indefinitely, adding more and more layers onto the duct. When
266+indefinitely, pushing more and more wires onto the top of the duct. When an
247−an entity finally produces a result, a layer is popped off the duct, and
267+entity finally produces a result, a wire is popped off the duct, and the result
248−the result is passed all the way back down.
268+is passed all the way back down, repeating the process of wire popping
249−
269+sequentially until the bottom of the duct is reached.
270+
250−In effect, a duct is an Arvo-level call stack. It's worth noting that
271+In effect, a duct is an Arvo-level call stack. It's worth noting that while in
251−while in traditional call stacks a function call happens synchronously
272+traditional call stacks a function call happens synchronously and returns
252−and returns exactly once. In Arvo, multiple moves can be sent at once,
273+exactly once. In Arvo, multiple moves can be sent at once, are evaluated
253−are evaluated asynchronously, and each one may be responded to zero or
274+asynchronously, and each one may be responded to zero or more times.
254−more times.
275+
255−
256−The point to take home is that whatever caused `++poke-urbit` to be
276+The point to take home is that whatever caused `++poke-urbit` to be called is
257−called is also the root cause for the network message we're trying to
277+also the root cause for the network message we're trying to send. Thus, we say
258−send. Thus, we say to send the network message along the given bone
278+to send the network message along the given bone `ost`.
259−`ost`.
279+
260−
280+##### Wire (path)
261−##### Wire ('tack on new layer to duct')
281+
262−
263−Of course, we have to push a new layer onto our duct before passing it
282+Of course, we have to push a new wire onto our duct before passing it along (or
264−along (or responding to it directly) anywhere. This layer can have any
283+responding to it directly) anywhere. This wire can have any data we want in it,
265−data we want in it, but we don't need anything specific here, so we just
284+but we don't need anything specific here, so we just use the wire `/sending`
266−use the wire `/sending` (`/elem1/elem2/elemN` is one syntax used to
285+(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
267−create `++path`s and `++wire`s of N elements). If we were expecting a
268−response (which we're not), it would come back along the `/sending`
286+elements). If we were expecting a response (which we're not), it would come back
269−wire, meaning that the path `/sending` will be passed back to the
287+along the `/sending` wire, meaning that the path `/sending` will be passed back
270−response handler as an argument. Although it's not required, it's
288+to the response handler as an argument. Although it's not required, it's
271−generally a good idea to make the wire human-readable for bug-handling
289+generally a good idea to make the wire human-readable for bug-handling purposes.
272−purposes.
273
290
274##### Term (sys-call)
291##### Term (sys-call)
275
292
276−Each move also has a `term`, composed of lowercase ASCII and/or `-`.
293+Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
277−This `term` has the sign `@tas`. In this case, out `term` is `%poke`,
294+has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
278−which is the name of the particular kind of move we're sending. You can
295+the particular kind of move we're sending. You can always use `%poke` to message
279−always use `%poke` to message an app. Other common names include
280−`%warp`, to read from the filesystem; `%wait`, to set a timer; and
296+an app. Other common names include `%warp`, to read from the filesystem;
281−`%them`, to send an http request.
297+`%wait`, to set a timer; and `%them`, to send an http request.
282
298
283The move ends with `*` (that is, any noun) since each type of move takes
299The move ends with `*` (that is, any noun) since each type of move takes
284−different data. In our case, a `%poke` move takes a target (urbit and
300+different data. In our case, a `%poke` move takes a target (urbit and app) and
285−app) and marked data, then pokes the arm of the corresponding mark on
301+marked data, then pokes the arm of the corresponding mark on that app on that
286−that app on that urbit with that data. `[to-urbit-address %pong]` is the
302+urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
287−target urbit and app, `%atom` is the `mark`, and`'howdy'` is the data.
303+`%atom` is the `mark`, and`'Pong'` is the data.
288
304
289When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
305When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
290The same mechanism is used for sending messages between apps on the same
306The same mechanism is used for sending messages between apps on the same
@@ -300,7 +316,7 @@ urbit as for sending messages between apps on different urbits.
300- Extend either of the apps in the first two exercises to accept input
316- Extend either of the apps in the first two exercises to accept input
301 over the network in the same way as `pong`.
317 over the network in the same way as `pong`.
302
318
303−- Modify `examples-pong` to print out a message when it receives
319+- Modify `pong.hoon` to print out a message when it receives
304 acknowledgement.
320 acknowledgement.
305
321
306- Write two apps, `even` and `odd`. When you pass an atom to `even`,
322- Write two apps, `even` and `odd`. When you pass an atom to `even`,
docs/arvo/state.md+94−79
@@ -8,102 +8,117 @@ title: State
8State
8State
9=====
9=====
10
10
11−In the last section we built a few small apps that sent moves. These
11+In the last section we built a few small apps that sent moves. These apps were
12−apps were entirely stateless, however. Most useful apps require some
12+entirely stateless, however. Most useful apps require some amount of state.
13−amount of state. Let's build a trivial stateful app. It'll keep a
13+Let's build a trivial stateful app. It'll keep a running the sum of all the
14−running the sum of all the atoms we poke it with. Here's
14+atoms we poke it with. Here's `examples/app/sum.hoon`:
15−`app/examples/sum.hoon`:
15+
16−
16+ :: Keeps track of the sum of all the atoms it has been
17− /? 314
17+ :: poked with and prints the sum out
18+ ::
19+ :::: /===/app/sum/hoon
20+ ::
18 !:
21 !:
22+ |%
23+ ++ move {bone card}
24+ ++ card $% $~
25+ ==
26+ --
19− |_ {bowl state/@}
27+ |_ {bow/bowl sum/@}
28+ ::
20− ++ poke-atom
29+ ++ poke-atom
21− |= arg/@
30+ |= tom/@
22− ^- {(list) _+>.$}
31+ ^- {(list move) _+>.$}
23− ~& [%so-far (add state arg)]
32+ ~& sum+(add sum tom)
24− [~ +>.$(state (add state arg))]
33+ [~ +>.$(sum (add sum tom))]
34+ ::
35+ ++ coup
36+ |= {wir/wire err/(unit tang)}
37+ ^- {(list move) _+>.$}
38+ ?~ err
39+ ~& sum+success+'Poke succeeded!'
40+ [~ +>.$]
41+ ~& sum+error+'Poke failed. Error:'
42+ ~& sum+error+err
43+ [~ +>.$]
44+ ::
25 --
45 --
26
46
27−We can start it with `|start %examples-sum`, and then run it:
47+We can start it with `|start %sum`, and then run it:
28
48
29− ~fintud-macrep:dojo> :examples-sum &atom 5
49+ ~fintud-macrep:dojo> :sum &atom 5
30− [%so-far 5]
50+ [%sum 5]
31 >=
51 >=
32− ~fintud-macrep:dojo> :examples-sum &atom 2
52+ ~fintud-macrep:dojo> :sum &atom 2
33− [%so-far 7]
53+ [%sum 7]
34 >=
54 >=
35− ~fintud-macrep:dojo> :examples-sum &atom 15
55+ ~fintud-macrep:dojo> :sum &atom 15
36− [%so-far 22]
56+ [%sum 22]
37 >=
57 >=
38
58
39We can see that app state is being saved, but when, where, and how?
59We can see that app state is being saved, but when, where, and how?
40
60
41−The state is stored as the second thing in the `|_` line. In our case,
61+The state is stored as the second thing in the `|_` line. In our case, it's
42−it's simply an atom named `state`. We change it by producing our
62+simply an atom named `sum`. We change it by producing our state not with
43−state not with `+>.$` (as before), but with
63+`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
44−`+>.$(state (add state arg))`. We've seen all these parts before, but
45−you might not recognize them.
64+parts before, but you might not recognize them.
46
65
47Recall in the first chapter that we recursed with the expression
66Recall in the first chapter that we recursed with the expression
48−`$(b (add 3 b))`. This meant "produce `$` with `b` changed to
67+`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
49−`(add 3 b)`. Similarly, `+>.$(state (add state arg))` means "produce
68+Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
50−`+>.$` (i.e. our context, which contains our state) with `state` changed
69+context, which contains our state) with `sum` changed to `(add sum tom)`.
51−to `(add state arg)`.
70+
52−
53−At a high level, then, when we handle state, we do it explicitly. It's
71+At a high level, then, when we handle state, we do it explicitly. It's passed in
54−passed in and produced explicitly. In Unix systems, application state is
72+and produced explicitly. In Unix systems, application state is just a block of
55−just a block of memory, which you need to serialize to disk if you want
73+memory, which you need to serialize to disk if you want to keep it around for
56−to keep it around for very long.
74+very long.
57−
75+
58−In Urbit, app state is a single (usually complex) value. In our example,
76+In Urbit, app state is a single (usually complex) value. In our example, we have
59−we have very simple state, so we defined `state/@`, meaning that our
77+very simple state, so we defined `sum/@`, meaning that our state is an atom.
60−state is an atom. Of course, `state` is just a name, and you're free to
78+Of course, `sum` is just a name, and you're free to name your state whatever
61−name your state whatever you like. But let's clarify a couple other
79+you like. But let's clarify a couple other things before we continue.
62−things before we continue.
80+
63−
64−First, `bowl` is a set of general global states. This set is managed by
81+First, `bowl` is a set of general global states. This set is managed by the
65−the system. It includes things like `now` (the current time), `our` (our
82+system. It includes things like `now` (the current time), `our` (our urbit
66−urbit identity), and `eny` (256 bits of guaranteed-fresh entropy). For
83+identity), and `eny` (256 bits of guaranteed-fresh entropy). For the full list
67−the full list of things in `++bowl`, search for `++ bowl` (note: two
84+of things in `++bowl`, search for `++ bowl` (note: two spaces) in
68−spaces) in `/arvo/zuse.hoon`.
85+`/arvo/zuse.hoon`.
69−
86+
70−> This is, perhaps, the most common way to learn Hoon. The easiest way
87+> This is, perhaps, the most common way to learn Hoon. The easiest way to learn
71−> to learn about an identifier you see in code is to search in
88+> about an identifier you see in code is to search in `/arvo/zuse.hoon` and
72−> `/arvo/zuse.hoon` and `/arvo/hoon.hoon` for it.\
73−> These "standard libraries" are usually simple to read. Since Urbit's
89+> `/arvo/hoon.hoon` for it.\\ These "standard libraries" are usually simple to
74−> codebase is less than 15000 lines of code combined, including the hoon
90+> read. Since Urbit's codebase is less than 15000 lines of code combined,
75−> parser, the compiler, and the `/arvo` microkernel, you can usually use
91+> including the hoon parser, the compiler, and the `/arvo` microkernel, you can
76−> the code and its comments as a reference doc.
92+> usually use the code and its comments as a reference doc.
77>
93>
78> You can also read
94> You can also read
79−> [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon)
95+> [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon) and
80−> and
81−> [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon)
96+> [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon) in your
82−> in your browser.
97+> browser.
83−
98+
84−The second thing we should clear up is this: Urbit needs no "serialize
99+The second thing we should clear up is this: Urbit needs no "serialize to disk"
85−to disk" step. Everything you produce in the app state is persistent
100+step. Everything you produce in the app state is persistent across calls to the
86−across calls to the app, restarts of the urbit, and even power failure.
101+app, restarts of the urbit, and even power failure. If you want to write to the
87−If you want to write to the Unix filesystem, you can, but it's not
102+Unix filesystem, you can, but it's not needed for persistence. Urbit has
88−needed for persistence. Urbit has transactional events, which makes it
103+transactional events, which makes it an [ACID operating
89−an [ACID operating system](https://en.wikipedia.org/wiki/ACID). Thus,
104+system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
90−you don't have to worry about persistence when programming in Urbit, or
105+persistence when programming in Urbit, or ever go through the hassle of having
91−ever go through the hassle of having to set up and write to a database.
106+to set up and write to a database.
92
107
93**Exercises**:
108**Exercises**:
94
109
95−- Modify `:examples-sum` to reset the counter when you poke it with 0.
110+- Modify `:sum` to reset the counter when you poke it with 0.
96
111
97−- Write an app that prints out the previous value you poked it with.
112+- Write an app called `last` that prints out the previous value you poked it with.
98 Sample output:
113 Sample output:
99
114
100−```
115+<!-- -->
116+
101−~fintud-macrep:dojo> :examples-last 7
117+ ~fintud-macrep:dojo> :last 7
102−[%last 0]
118+ [%last 0]
103−>=
119+ >=
104−~fintud-macrep:dojo> :examples-last [1 2 3]
120+ ~fintud-macrep:dojo> :last [1 2 3]
105−[%last 7]
121+ [%last 7]
106−>=
122+ >=
107−~fintud-macrep:dojo> :examples-last 'howdy'
123+ ~fintud-macrep:dojo> :last 'howdy'
108−[%last [1 2 3]]
124+ [%last [1 2 3]]
109−```
docs/arvo/subscriptions.md+218−140
@@ -13,62 +13,124 @@ want to subscribe to updates from another app. You could build a
13subscription model out of one-way pokes, but it's such a common pattern
13subscription model out of one-way pokes, but it's such a common pattern
14that it's built into arvo.
14that it's built into arvo.
15
15
16−Let's take a look at two apps, `:examples-source` and `:examples-sink`.
16+Let's take a look at two apps, `:source` and `:sink`. First,
17−First, `:examples-source`:
17+`:source`:
18−
18+
19− /? 314
19+ :: Sends subscription updates to sink.hoon
20+ ::
21+ :::: /===/app/source/hoon
22+ ::
20 !:
23 !:
24+ ::
21 |%
25 |%
22− ++ move {bone $diff mark *}
26+ ++ move {bone card}
27+ ++ card $% {$diff diff-contents}
28+ ==
29+ ++ diff-contents $% {$noun *}
30+ ==
23 --
31 --
32+ ::
24− |_ {hid/bowl state/$~}
33+ |_ {bow/bowl $~}
34+ ::
25− ++ poke-noun
35+ ++ poke-noun
26− |= arg/*
36+ |= non/*
27 ^- {(list move) _+>.$}
37 ^- {(list move) _+>.$}
28 :_ +>.$
38 :_ +>.$
29− %+ turn (prey /example-path hid)
39+ %+ turn (prey /example-path bow)
30− |=({o/bone *} `move`[o %diff %noun arg])
40+ |=({o/bone *} [o %diff %noun non])
41+ ::
31− ++ peer-example-path
42+ ++ peer-example-path
32 |= pax/path
43 |= pax/path
33 ^- {(list move) _+>.$}
44 ^- {(list move) _+>.$}
34− ~& [%subscribed-to pax=pax]
45+ ~& source+peer-notify+'Someone subscribed to you!'
46+ ~& source+[ship+src.bow path+pax]
47+ [~ +>.$]
48+ ::
49+ ++ coup
50+ |= {wir/wire err/(unit tang)}
51+ ^- {(list move) _+>.$}
52+ ?~ err
53+ ~& source+success+'Poke succeeded!'
54+ [~ +>.$]
55+ ~& source+error+'Poke failed. Error:'
56+ ~& source+error+err
57+ [~ +>.$]
58+ ::
59+ ++ reap
60+ |= {wir/wire err/(unit tang)}
61+ ^- {(list move) _+>.$}
62+ ?~ err
63+ ~& source+success+'Peer succeeded!'
64+ [~ +>.$]
65+ ~& source+error+'Peer failed. Error:'
66+ ~& source+error+err
35 [~ +>.$]
67 [~ +>.$]
68+ ::
36 --
69 --
37
70
38−And secondly, `:examples-sink`:
71+And secondly, `:sink`:
39−
72+
40− /? 314
73+ :: Sets up a simple subscription to source.hoon
74+ ::
75+ :::: /===/app/sink/hoon
76+ ::
77+ !:
41 |%
78 |%
42− ++ move {bone card}
79+ ++ move {bone card}
43− ++ card
44− $% {$peer wire {@p term} path}
80+ ++ card $% {$peer wire dock path}
45− {$pull wire {@p term} $~}
81+ {$pull wire dock $~}
46− ==
82+ ==
47 --
83 --
48− !:
84+ ::
49− |_ {bowl available/?}
85+ |_ {bow/bowl val/?}
86+ ::
50− ++ poke-noun
87+ ++ poke-noun
51− |= arg/*
88+ |= non/*
52 ^- {(list move) _+>.$}
89 ^- {(list move) _+>.$}
53− ?: &(=(%on arg) available)
90+ ?: &(=(%on non) val)
54− [[[ost %peer /subscribe [our %source] /example-path] ~] +>.$(available |)]
91+ :_ +>.$(val |)
55− ?: &(=(%off arg) !available)
92+ :~ :* ost.bow
93+ %peer
94+ /subscribe
95+ [our.bow %source]
96+ /example-path
97+ ==
98+ ==
99+ ?: &(=(%off non) !val)
100+ :_ +>.$(val &)
56− [[[ost %pull /subscribe [our %source] ~] ~] +>.$(available &)]
101+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
102+ ~& ?: val
103+ sink+unsubscribed+'You are now unsubscribed!'
57− ~& ?:(available %not-subscribed %subscribed)
104+ sink+subscribed+'You are now subscribed!'
58 [~ +>.$]
105 [~ +>.$]
106+ ::
59− ++ diff-noun
107+ ++ diff-noun
60− |= {wir/wire arg/*}
108+ |= {wir/wire non/*}
61 ^- {(list move) _+>.$}
109 ^- {(list move) _+>.$}
62− ~& [%received-data arg]
110+ ~& sink+received-data+'You got something!'
111+ ~& sink+data+non
63 [~ +>.$]
112 [~ +>.$]
64− ++ reap
113+ ::
114+ ++ coup
65− |= {wir/wire error/(unit tang)}
115+ |= {wir/wire err/(unit tang)}
66 ^- {(list move) _+>.$}
116 ^- {(list move) _+>.$}
67− ?~ error
117+ ?~ err
68− ~& %successfully-subscribed
118+ ~& sink+success+'Poke succeeded!'
69− [~ +>.$]
119+ [~ +>.$]
70− ~& [%subscription-failed error]
120+ ~& sink+error+'Poke failed. Error:'
121+ ~& sink+error+err
71 [~ +>.$]
122 [~ +>.$]
123+ ::
124+ ++ reap
125+ |= {wir/wire err/(unit tang)}
126+ ^- {(list move) _+>.$}
127+ ?~ err
128+ ~& sink+success+'Peer succeeded!'
129+ [~ +>.$]
130+ ~& sink+error+'Peer f ailed. Error:'
131+ ~& sink+error+err
132+ [~ +>.$]
133+ ::
72 --
134 --
73
135
74Cheat sheet:
136Cheat sheet:
@@ -120,41 +182,43 @@ Cheat sheet:
120
182
121Here's some sample output of the two working together:
183Here's some sample output of the two working together:
122
184
123−
124− ~fintud-macrep:dojo> |start %examples-source
185+ ~fintud-macrep:dojo> |start %source
125 >=
186 >=
126− ~fintud-macrep:dojo> |start %examples-sink
187+ ~fintud-macrep:dojo> |start %sink
127 >=
188 >=
128− ~fintud-macrep:dojo> :examples-sink %on
189+ ~fintud-macrep:dojo> :sink %on
129− [%subscribed-to pax=/example-path]
190+ [%source %peer-notify 'Someone subscribed to you!']
130− %successfully-subscribed]
191+ [%source [%ship ~fintud-macrep] %path /]
192+ [%sink %success 'Peer succeeded!']
131 >=
193 >=
132− ~fintud-macrep:dojo> :examples-source 5
194+ ~fintud-macrep:dojo> :source 5
133− [%received-data 5]
195+ [%sink %received-data 'You got something!']
196+ [%sink %data 5]
134 >=
197 >=
135− ~fintud-macrep:dojo> :examples-sink %off
198+ ~fintud-macrep:dojo> :sink %off
136 >=
199 >=
137− ~fintud-macrep:dojo> :examples-source 6
200+ ~fintud-macrep:dojo> :source 6
138 >=
201 >=
139− ~fintud-macrep:dojo> :examples-sink %on
202+ ~fintud-macrep:dojo> :sink %on
140− [%subscribed-to pax=/example-path]
203+ [%source %peer-notify 'Someone subscribed to you!']
141− %successfully-subscribed]
204+ [%source [%ship ~fintud-macrep] %path /]
205+ [%sink %success 'Peer succeeded!']
142 >=
206 >=
143− ~fintud-macrep:dojo> :examples-source 7
207+ ~fintud-macrep:dojo> :source 7
144− [%received-data 7]
208+ [%sink %received-data 'You got something!']
209+ [%sink %data 7]
145 >=
210 >=
146
211
147−### :examples-source
212+### :source
148
213
149Hopefully you can get a sense for what's happening here. When we poke
214Hopefully you can get a sense for what's happening here. When we poke
150−`:examples-sink` with `%on`, `:examples-sink` subscribes to
215+`:sink` with `%on`, `:sink` subscribes to `:source`,
151−`:examples-source`, and so whenever we poke `:examples-source`,
216+and so whenever we poke `:source`, `:sink` gets the update and
152−`:examples-sink` gets the update and prints it out. Then we unsubscribe
217+prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
153−by poking `:examples-sink` with `%off`, and `:examples-sink` stops
154−getting updates. We then resubscribe.
218+`:sink` stops getting updates. We then resubscribe.
155
219
156−There's a fair bit going on in this code. Let's look at
220+There's a fair bit going on in this code. Let's look at `:source`
157−`:examples-source` first.
221+first.
158
222
159Our definition of `move` is fairly specific, since we're only going to
223Our definition of `move` is fairly specific, since we're only going to
160sending one kind of move. The `%diff` move is a subscription update, and
224sending one kind of move. The `%diff` move is a subscription update, and
@@ -167,18 +231,16 @@ the discussion of ducts, a layer gets popped off the duct rather than
167added to it. This is why no wire is needed for the move -- we won't
231added to it. This is why no wire is needed for the move -- we won't
168receive anything in response to it.
232receive anything in response to it.
169
233
170−Anyways, there're two functions inside the `|_`. We already know when
234+Anyways, there are four functions (arms) inside the `|_`. We already know when
171−`++poke-noun` is called. `++peer` is called when someone tries to
235+`++poke-noun` is called. `++peer-example-path` is called when someone tries to
172−subscribe to our app. Of course, you don't just subscribe to an app; you
236+subscribe to our app. Of course, you don't just subscribe to an app; you
173−subscribe to a path on that app. This path comes in as the argument to
237+subscribe to a path on that app. This path comes in as the argument to `++peer`.
174−`++peer`.
238+
175−
176−In our case, we don't care what path you subscribed on, and all we do is
239+In our case, we don't care what path you subscribed on, and all we do is print
177−print out that you subscribed. Arvo keeps track of your subscriptions,
240+out that you subscribed. Arvo keeps track of your subscriptions, so you don't
178−so you don't have to. You can access your subscribers by looking at
241+have to. You can access your subscribers by looking at `sup` in the bowl that's
179−`sup` in the bowl that's passed in. `sup` is of type
180−`(map bone {@p path})`, which associates bones with the urbit who
242+passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
181−subscribed, and which path they subscribed on. If you want to
243+the urbit who subscribed, and which path they subscribed on. If you want to
182communicate with your subscribers, send them messages along their bone.
244communicate with your subscribers, send them messages along their bone.
183
245
184`++poke-noun` "spams" the given argument to all our subscribers.
246`++poke-noun` "spams" the given argument to all our subscribers.
@@ -187,83 +249,99 @@ same as `[b a]`. It's just a convenient way of formatting things when
187the first thing in a cell is much more complicated than the second.
249the first thing in a cell is much more complicated than the second.
188Thus, we're producing our state unchanged.
250Thus, we're producing our state unchanged.
189
251
190−Our list of moves is the result of a call to `++turn`. `++turn` is what
252+Our list of moves is the result of a call to `++turn`. `++turn` is what many
191−many languages call "map" -- it runs a function on every item in a list
253+languages call "map" -- it runs a function on every item in a list and collects
192−and collects the results in a list. The list is `(prey /example-path hid)`
254+the results in a list. The list is `(prey /example-path bow)` and the function
193−and the function is the `|=` line right after it.
255+is the `|=` line right after it.
194
256
195−`++prey` is a standard library function defined in `zuse`. It takes a
257+`++prey` is a standard library function defined in `zuse.hoon`. It takes a path
196−path and a bowl and gives you a list of the subscribers who are
258+and a bowl and gives you a list of the subscribers who are subscribed on a path
197−subscribed on a path that begins with the given path. "Prey" is short
259+that begins with the given path. "Prey" is short for "prefix".
198−for "prefix".
199
260
200Now we have the list of relevant subscribers. This a list of triples,
261Now we have the list of relevant subscribers. This a list of triples,
201−`{bone @p path}`, where the only thing we really need is the bone,
262+`{bone @p path}`, where the only thing we really need is the bone, because we
202−because we don't need to know their urbit or what exact path they
263+don't need to know their urbit or what exact path they subscribed on. Thus, our
203−subscribed on. Thus, our transformer function takes `{o/bone *}` and
264+transformer function takes `{o/bone *}` and produces `[o %diff %noun non]`,
204−produces `[o %diff %noun arg]`, which is a move that provides bone `o`
265+which is a move that provides bone `o` with this subscription update:
205−with this subscription update: `[%noun arg]`". This is fairly dense
266+`[%noun non]`". This is fairly dense code, but what it's doing is
206−code, but what it's doing is straightforward.
267+straightforward!
207−
268+
208−### :examples-sink
269+### :sink
209−
270+
210−`:examples-source` should now make sense. `:examples-sink` is a little
271+`:source` should now make sense. `:sink` is a little longer, but not much more
211−longer, but not much more complicated.
272+complicated.
212−
273+
213−In `:examples-sink`, our definition of of `++move` is different. All
274+In `:sink`, our definition of of `++move` is different. All moves start
214−moves start with a `bone`, and we conventionally refer to the second
275+with a `bone`, and we conventionally refer to the second half as the "card", so
215−half as the "card", so that we can say a move is an action that sends a
276+that we can say a move is an action that sends a card along a bone.
216−card along a bone.
277+
217−
218−We have two kinds of cards here: we `%peer` to start a subscription, and
278+We have two kinds of cards here: we `%peer` to start a subscription, and we
219−we `%pull` to stop it. Both of these are "forward" moves that may
279+`%pull` to stop it. Both of these are "forward" moves that may receive a
220−receive a response, so they need a wire to tack onto the duct before
280+response, so they need a wire to tack onto the duct before they pass it on. They
221−they pass it on. They also need a target, which is a pair of an urbit
281+also need a target, which is a pair of an urbit and an app name. Additionally,
222−and an app name. Additionally, `%peer` needs a path on that app to
223−subscribe too. `%pull` doesn't need this, because its semantics are to
282+`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
224−cancel any subscriptions coming over this duct. If your bone and wire
283+because its semantics are to cancel any subscriptions coming over this duct. If
225−are the same as when you subscribed, then the cancellation will happen
284+your bone and wire are the same as when you subscribed, then the cancellation
226−correctly.
285+will happen correctly.
227−
286+
228−The only state we need for `:examples-sink` is a boolean to indicate
287+The only state we need for `:sink` is a boolean to indicate whether
229−whether we're already subscribed to `:examples-source`. We use
288+we're already subscribed to `:source`. We use `val/?`, where `?`
230−`available/?`, where `?` is the sign of type boolean (similar to `*`,
289+is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
231−`@`), which defaults to true (that is, `0`).
290+is, `0`).
232
291
233In `++poke-noun` we check our input to see both if it's `%on` and we're
292In `++poke-noun` we check our input to see both if it's `%on` and we're
234−available. If so, we produce the move to subscribe to
293+available (`val` is true). If so, we produce the move to subscribe to
235−`:examples-source`:
294+`:source`:
236−
295+
296+ :~ :* ost.bow
297+ %peer
298+ /subscribe
299+ [our.bow %source]
237− [ost %peer /subscribe [our %source] /example-path]
300+ /example-path
238−
301+ ==
302+ ==
303+
239−Also, we set available to false (`|`) with `+>.$(available |)`.
304+Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
240−
305+Remember that the `:_` constructs an inverted cell, with the first child
306+(`+>.$(val |` in our case) as the tail and the second child as the head. Here,
307+the cell we produce when our subscription is `%on` and `val` is true has a
308+head with our new state where `val` is set to false and a tail of our list of
309+moves, which is shown in the code block above.
310+
241−Otherwise, if our input is `%off` and we're already subscribed (i.e.
311+Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
242−`available` is false), then we unsubscribe from `:examples-source`:
312+is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
243−
313+again using our handy inverted cell constructor mold `:_`:
314+
315+ :_ +>.$(val &)
244− [ost %pull /subscribe [our %source] ~]
316+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
245
317
246It's important to send over the same bone and wire (`/subscribe`) as the
318It's important to send over the same bone and wire (`/subscribe`) as the
247one we originally subscribed on.
319one we originally subscribed on.
248
320
249−We also set `available` to true (`&`).
321+If neither of these cases are true, then we print our current subscription
322+state, based on whether `val` is true or false, and return a cell containing
323+a null list of moves and our unchanged app state:
324+
325+ ~& ?: val
326+ sink+unsubscribed+'You are now unsubscribed!'
327+ sink+subscribed+'You are now subscribed!'
328+ [~ +>.$]
250
329
251−If neither of these cases are true, then we print our current
330+`++diff-noun` is called when we get a `%diff` update along a subscription with a
252−subscription state.
331+mark of `noun`. `++diff-noun` is given the wire that we originally passed with
332+the `%peer` subscription request along and the data we got back. In our case we
333+just print out the data:
253
334
254−`++diff-noun` is called when we get a `%diff` update along a
335+ ~& sink+received-data+'You got something!'
255−subscription with a mark of `noun`. `++diff-noun` is given the wire that
336+ ~& sink+data+non
256−we originally passed with the `%peer` subscription request along and the
257−data we got back. In our case we just print out the data.
258
337
259`++reap` is called when we receive an acknowledgment as to whether the
338`++reap` is called when we receive an acknowledgment as to whether the
260−subscription was handled successfully. You can remember that `++reap` is
339+subscription was handled successfully. You can remember that `++reap` is the
261−the counterpart to `++peer` as it's pronounced like 'peer' backwards.
340+counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
262−Similarly, `coup` is similar to 'poke' backwards.
341+`coup` is similar to 'poke' backwards.
263−
342+
264−Moving forward, `++reap` is given the wire we attempted to subscribe
343+Moving forward, `++reap` is given the wire we attempted to subscribe over,
265−over, possibly along with an error message in cases of failure.
344+possibly along with an error message in cases of failure. `(unit type)` means
266−`(unit type)` means "either `~` or `[~ type]`, which means it's used
345+"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
267−like Haskell's "maybe" or C's nullability. If `error` is `~`, then the
268−subscription was successful and we tell that to the user. Otherwise, we
346+nullability. If `err` is `~`, then the subscription was successful and we tell
269−print out the error message.
347+that to the user. Otherwise, we print out the error message.