on master help sign in
Merge pull request #210 from mattlevan/arvo

Progress on updating the Arvo docs to match the updated examples

commitfc698e8b355c6ad8cc56386873cf5070549beda8 authorKeaton Dunsford <keaton.dunsford@gmail.com> dateMon 16 Oct 2017, 13:07 (9 years ago) parent58b9f06605bf79
4 files changed+574−444
docs/arvo/basic.md+89−68 docs/arvo/network.md+173−157 docs/arvo/state.md+94−79 docs/arvo/subscriptions.md+218−140
docs/arvo/basic.md+89−68
@@ -14,32 +14,68 @@ fundamentals of [Hoon](/docs/hoon/). To do this, we'll walk through two simple
1414programs: the first [Project Euler](https://projecteuler.net/) problem
1515and [fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
1616
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
1818[examples repo](https://github.com/urbit/examples) into it.
1919
20−If you haven't installed urbit yet, check out the [installation
21−instructions](/docs/using/install). Once urbit is installed, take a look
22−at the [basic operation](/docs/using/admin) of your urbit.
20+## Installation
2321
24−If you haven't copied in the examples repo, running the following
25−commands from your urbit directory should do the trick:
22+First, you'll need a running urbit. Follow our urbit.org [install
23+instructions](https://urbit.org/docs/using/install), then
24+[setup](https://urbit.org/docs/using/setup) and urbit.
2625
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.
2831
29−```
30−~fintud-macrep:dojo> |mount %
31−```
32+### Network install
3233
33−Then, copy the example into it
34+In your urbit's `:dojo`, run the command:
3435
35−```
36−$ cp -r {urbit-examples}/gall/*/* {your-pier}/home/
37−$ cp -r {urbit-examples}/dojo/*/* {your-pier}/home/
38−```
36+ ~your-urbit:dojo> |sync %examples ~ropmev-pocseb %examples
37+
38+Depending on network traffic, this initial merge and sync could take anywhere
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!
3975
4076Run an example to ensure it worked:
4177
42− ~fintud-macrep:dojo> +examples-euler1
78+ ~fintud-macrep:dojo> +project-euler/p1
4379 233.168
4480
4581Euler 1
@@ -53,42 +89,44 @@ Let's check out the code for Euler 1. First, the problem:
5389 Find the sum of all the multiples of 3 or 5 below 1000.
5490
5591Here is the hoon solution (which should be in your pier directory under
56−`/gen/examples/euler1`):
92+`/examples/gen/project-euler/p1`):
5793
58− :: project euler 1
59− :: https://projecteuler.net/problem=1
60− :: run in dojo with +examples-euler1
94+ :: Project Euler 1
95+ :: https://projecteuler.net/problem=1
6196 ::
62− :::: /hoon/euler1/examples/gen
63− ::
64− :- %say |= *
97+ :: run in dojo with:
98+ :: ~your-urbit:dojo/examples> +project-euler/p1
99+ ::
100+ :::: /===/gen/project-euler/p1/hoon
101+ ::
102+ !:
103+ ::
104+ :- %say |= *
65105 :- %noun
66106 =< (sum 1.000)
67107 ::
68− :::: ~sivtyv-barnel
69− ::
70108 |%
71109 ++ three
72− |= a/@
73− =| b/@
74− |- ^- @u
110+ |= a/@
111+ =| b/@
112+ |- ^- @u
75113 ?: (lth a b)
76− 0
114+ 0
77115 (add b $(b (add 3 b)))
78116 ::
79117 ++ five
80− |= a/@
81− =| b/@
118+ |= a/@
119+ =| b/@
82120 |- ^- @
83121 ?: (lte a b)
84− 0
122+ 0
85123 ?: =((mod b 3) 0)
86− $(b (add b 5))
124+ $(b (add b 5))
87125 (add b $(b (add b 5)))
88126 ::
89− ++ sum
127+ ++ sum
90128 |= a/@u
91− (add (five a) (three a))
129+ (add (five a) (three a))
92130 --
93131
94132> 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
97135> Really. For a more detailed explanation of when to use spaces vs.
98136> gaps, see the syntax section before the first exercises.
99137
100−### Lines 1-11:
138+### Lines 1-13:
101139
102140Any line that begins with `::` is a comment.
103141
@@ -117,8 +155,8 @@ rune takes a specific number of children, either expressions formed by
117155other runes or literals that produce their own value (some runes take
118156*N* children, and are usually closed with `==`).
119157
120−For example, the rune `?:` from line 18 is the classic 'if-then-else'
121−statement, and thus takes three children:
158+For example, the rune `?:` from line 20 is the classic 'if-then-else' statement,
159+and thus takes three children:
122160
123161 ?: (lth a b) :: if first child evals to true
124162 0 :: then produce result of second
@@ -149,32 +187,15 @@ See the entire naming scheme below.
149187
150188Using this scheme, we would pronounce `?:` as 'wutcol'.
151189
152−For those who prefer to use reserved words to form expressions, you can
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`:
190+### Lines 14-37
156191
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
172−wrapped in a `|%` ('[barcen](../../hoon/twig/bar-core/cen-core/)'), which produces a core. Cores are a
173−fundamental datatype in Hoon, similar to a struct, class, or object. A
174−core is just a map of names to any kind of code, whether it be functions
175−or data. Each element in this map begins with a `++` followed by the
176−name and the corresponding code. Since `|%` takes an arbitrary number of
177−children, it needs to be closed with a `--`.
192+Now let's quickly walk through this code line-by-line. Lines 14-37 are wrapped
193+in a `|%` ('[barcen](../../hoon/twig/bar-core/cen-core/)'), which produces a
194+core. Cores are a fundamental datatype in Hoon, similar to a struct, class, or
195+object. A core is just a map of names to any kind of code, whether it be
196+functions or data. Each element, called an arm, in this map begins with a `++`
197+followed by the name and the corresponding code. Since `|%` takes an arbitrary
198+number of children, it needs to be closed with a `--`.
178199
179200> `++` ('luslus') is not technically a rune, since it is only used in
180201> core syntax, as shown above.
@@ -184,7 +205,7 @@ Let's step into each of the three arms within our core.
184205### `++ sum`
185206
186207 ++ sum
187− |= a/@
208+ |= a/@u
188209 (add (five a) (three a))
189210 --
190211
@@ -195,10 +216,10 @@ takes two children:
195216 one: `a`, which is required to be an atom or natural number, denoted
196217 by `@`.
197218
198−2. The body of the function itself, which is executed when the function
199− is called (in this case, with `(sum 1.000)`). This particular
200− function adds the results of evaluating the gates `++ five` and
201− `++three` with each of their respective input parameters set to `a`.
219+2. The body of the function itself, which is executed when the function is
220+ called (in this case, with `(sum 1.000)`). This particular function adds the
221+ results of evaluating the gates `++five` and `++three` with each of their
222+ respective input parameters set to `a`.
202223
203224### ++ three
204225
docs/arvo/network.md+173−157
@@ -11,70 +11,73 @@ Network messages
1111Now we've learned enough Hoon to do more interesting things. Let's get
1212our planets to talk to each other.
1313
14−All we've written up until now are just shell commands that produce a
15−value and then disappear. To listen for and receive messages from other
16−planets, we'll need an app. Let's look at a very simple one:
14+All we've written up until now are just shell commands that produce a value and
15+then disappear. To listen for and receive messages from other planets, we'll
16+need an app. Let's look at a very simple one, `echo.hoon`:
1717
1818 :: Accepts any noun from dojo and prints it out
1919 ::
20− :::: /hoon/echo/examples/app
20+ :::: /===/app/echo/hoon
2121 ::
22− /? 314
23− !:
24− |_ {bowl state/$~}
25− ++ poke-noun
26− |= arg/*
27− ^- {(list) _+>.$}
28− ~& [%argument arg]
29− [~ +>.$]
30− --
22+ !: :: enables debug printfs
23+ |% :: forms a core with subject as payload
24+ ++ move {bone card} :: defines echo app's arvo move mold
25+ ++ card $% $~ :: defines card (data) mold as null tagged union
26+ == :: end of mold definition; see $%
27+ -- :: end of card arm definition
28+ :: ::
29+ |_ {bow/bowl $~} :: forms a core with bowl (app state) as sample
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
3136
3237This is a very simple app that does only one thing. If you poke it with
3338a value, it prints that value out. To try this out, you have to start
3439the app, then you can poke it from the command line with the following
3540commands:
3641
37− ~fintud-macrep:dojo> |start %examples-echo
38− 'prep'
42+ ~fintud-macrep:dojo> |start %echo
3943 >=
40− ~fintud-macrep:dojo> :examples-echo 5
41− [%argument 5]
44+ ~fintud-macrep:dojo> :echo 5
45+ [%echo %noun 5]
4246 >=
4347 ~fintud-macrep:dojo> :examples-echo [1 2]
44− [%argument [1 2]]
48+ [%echo %noun [1 2]]
4549 >=
4650
47−> There is currently a bug where the `%argument` lines are printed
48−> *above* the line you entered, so your output may not look exactly like
49−> this. `>=` means that a command was successfully received and
50−> executed.
51+> There is currently a bug where the `[%echo %noun *]` lines are printed *above*
52+> the line you entered, so your output may not look exactly like this. `>=`
53+> means that a command was successfully received and executed.
5154
5255Most of the app code should be simple enough to guess its function. The
5356important part of this code is the definition of `++poke-noun`.
5457
55−Once an app starts, it's always running in the background and you
56−interact with it by sending it messages. The most straightforward way to
57−do that is to poke it from the command line, which we we did with
58−`:echo 5` (`:[app-name] [argument(s)]`).
58+Once an app starts, it's always running in the background and you interact with
59+it by sending it messages. The most straightforward way to do that is to poke it
60+from the command line, which we we did with `:echo 5`
61+(`:[app-name] [argument(s)]`).
5962
60−In this case, `++poke-noun` takes an argument `arg` and prints it out
61−with `~&` ([sigpam](../../hoon/twig/sig-hint/pam-dump/)). This is an unusual
62−rune that formally "does nothing", but the interpreter detects it and
63−printfs the first child, before executing the second as if the first
64−didn't exist. This is a slightly hacky way of printing to the console,
63+In this case, `++poke-noun` takes an argument (*sample*) `arg` and
64+prints it to dojo with `~&` ([sigpam](../../hoon/twig/sig-hint/pam-dump/)).
65+This is an unusual rune that formally "does nothing", but the interpreter
66+detects it and printfs the first child, before executing the second as if the
67+first didn't exist. This is a slightly hacky way of printing to the console,
6568but we'll get to the correct way later on.
6669
67−But what does `++poke-noun` produce? Recall that `^-` casts to a type.
68−In this case, it's declaring that the end result of the function will be of
69−type `{(list) _+>.$}`. But what does this mean?
70+But what does `++poke-noun` produce? Recall that `^-` casts to a type. In this
71+case, it's declaring that the end result (*product*) of the function
72+(`++poke-noun`'s *gate*) will be of type `{(list) _+>.$}`. But what does this
73+mean?
7074
71−The phrase to remember is "a list of moves and our state". Urbit is a
72−message passing system, so whenever we want to do something that
73−interacts with the rest of the system, we send a message. Thus, a move
74−is Arvo's equivalent of a syscall. The first thing that `++poke-noun`
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,
77−`~` (in the `[~ +>.$]` line).
75+The phrase to remember is "a list of moves and our state". Urbit is a message
76+passing system, so whenever we want to do something that interacts with the rest
77+of the system, we send a message. Thus, a move is Arvo's equivalent of a
78+syscall. The first thing that `++poke-noun` produces is a list of messages,
79+called "moves". In this case, we don't actually want the system to do anything,
80+so we produce the empty list, `~` (in the `[~ +>.$]` line).
7881
7982The second thing `++poke-noun` produces is our state. `+>.$` refers to a
8083particular 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
8588`/app/examples/echo/hoon` to reflect the code below). Say we want to
8689only accept a number, and then print out the square of that number.
8790
88− /? 314
89− !:
90− |_ {bowl state/$~}
91+ :: Accepts an atom from the dojo and squares it.
9192 ::
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 $~}
92103 ++ poke-atom
93− |= arg/@
94− ^- {(list) _+>.$}
95− ~& [%square (mul arg arg)]
96− [~ +>.$]
97− --
104+ |= tom/@
105+ ^- {(list move) _+>.$}
106+ ~& square+(mul tom tom)
107+ [~ +>.$]
108+ --
98109
99−A few things have changed. Firstly, we no longer accept arbitrary nouns
100−because we can only square atoms (integers, in this case an unsigned
101−one). Thus, our argument is now `arg/@`. Secondly, it's `++poke-atom`
102−rather than `++poke-noun`.
110+A few things have changed. Firstly, we no longer accept arbitrary nouns because
111+we can only square atoms (integers, in this case an unsigned one). Thus, our
112+argument is now `tom/@`. Secondly, it's `++poke-atom` rather than `++poke-noun`.
103113
104114Intro to marks
105115==============
@@ -124,9 +134,9 @@ using `&[mark]`. Try the following commands:
124134
125135 ~fintud-macrep:dojo> |start %square
126136 >=
127− ~fintud-macrep:dojo> :examples-square 6
137+ ~fintud-macrep:dojo> :square 6
128138 gall: %square: no poke arm for noun
129− ~fintud-macrep:dojo> :examples-square &atom 6
139+ ~fintud-macrep:dojo> :square &atom 6
130140 [%square 36]
131141 >=
132142
@@ -143,68 +153,79 @@ so we'll be getting quite used to them.
143153Sending a message to another urbit
144154==================================
145155
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`:
147157
148− /? 314
158+ :: Allows one urbit to send the string 'Pong' to
159+ :: another urbit.
160+ ::
161+ :::: /===/app/pong/hoon
162+ ::
163+ !:
149164 |%
150− ++ move {bone term wire *}
165+ ++ move {bone card}
166+ ++ card $% {$poke wire dock poke-contents}
167+ ==
168+ ++ poke-contents $% {$atom @}
169+ ==
151170 --
152− !:
153− |_ {bowl state/$~}
171+ |_ {bow/bowl $~} ::< stateless
154172 ::
155173 ++ poke-urbit
156− |= to/@p
174+ |= to/ship
157175 ^- {(list move) _+>.$}
158− [[[ost %poke /sending [to dap] %atom 'howdy'] ~] +>.$]
176+ ~& pong+'Outgoing pong!'
177+ :_ +>.$
178+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
159179 ::
160180 ++ poke-atom
161− |= arg/@
181+ |= tom/@
162182 ^- {(list move) _+>.$}
163− ~& [%receiving (@t arg)]
183+ ~& pong+'Incoming pong!'
184+ ~& pong+received+`@t`tom
164185 [~ +>.$]
165186 ::
166187 ++ coup |=(* [~ +>.$])
188+ ::
167189 --
168−
190+
169191Run it with these commands:
170192
171− ~fintud-macrep:dojo> |start %examples-pong
193+ ~fintud-macrep:dojo> |start %pong
172194 >=
173− ~fintud-macrep:dojo> :examples-pong &urbit ~sampel-sipnym
195+ ~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
174196 >=
175197
176−Replace `~sampel-sipnym` with another urbit. The easiest thing to do is
177−to start a comet, a free and disposable Urbit identity. If you don't know
178−how to start a comet, see [the user setup section](/docs/using/setup/).
179−Don't forget to start the `%examples-pong` app on that urbit, too. You
180−should see, on the foreign urbit, this output:
181−
182− [%receiving 'howdy']
183−
184−Most of the code should be straightforward. In `++poke-atom`, the only
185−new thing is the expression `(@t arg)`, which is the type `@t` being
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
188−functions, they serve as a validator function called a "clam" -- that
189−is, a function whose domain is all nouns, and range is the given type
190−(in this case, `@t`).
191−
192−In simpler terms, if a clam is passed a value of its own type, it
193−produces that value. Otherwise, it produces the default value (aka the
194−"bunt") of its type. Here we call this `@t` function on the argument.
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
199−urbit identity, and the Hoon type associated with it is `@p` (the "p"
198+Replace `~sampel-sipnym` with another urbit. The easiest thing to do is to start
199+a comet, a free and disposable Urbit identity. If you don't know how to start a
200+comet, see [the user setup section](/docs/using/setup/). Don't forget to start
201+the `%pong` app on that urbit, too. You should see, on the foreign
202+urbit, this output:
203+
204+ [%pong 'Incoming pong!']
205+ [%pong %received 'Pong']
206+
207+Most of the code should be straightforward. In `++poke-atom`, the only new thing
208+is the expression `` `@t`tom ``, which is *casting* the argument `tom` to type
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",
212+and they serve as validator functions-- that is, functions whose domain is all
213+nouns, and range is the given type (in this case, `@t`). Clams will "bunt" the
214+default value of the mold whereas casts (`@t`tom) may `nest-fail` if the
215+argument passed to it does not fit. An example of such a failure case is
216+passing a cell to an atom: `` `@`[1 2] ``. Using a clam here instead
217+(`(@ [1 2])`) will bunt the default value of `@`, which is `0`. Try it in dojo!
218+
219+The more interesting part is in `++poke-urbit`. The `urbit` mark is an urbit
220+identity, and the Hoon type associated with it is `ship` or `@p` (the "p"
200221stands for "phonetic base").
201222
202−Recall that in a `++poke` arm we produce "a list of moves and our
203−state". Until now, we've left the list of moves empty, since we haven't
204−wanted to tell Arvo to do anything in particular. Now we want to send a
205−message to another urbit. Thus, we produce a list with one element:
223+Recall that in a `++poke` arm we produce "a list of moves and our state". Until
224+now, we've left the list of moves empty, since we haven't wanted to tell Arvo to
225+do anything in particular. Now we want to send a message to another urbit. Thus,
226+we produce a list with one element:
206227
207− [ost %poke /sending [to-urbit-address %pong] %atom 'howdy']
228+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
208229
209230### Moves
210231
@@ -218,73 +239,68 @@ Let's walk through each of these elements step by step.
218239
219240#### Bones ("cause")
220241
221−If you look up `++bone` in `hoon.hoon`, you'll see that it's a number
222−(`@ud`), and that it's an opaque reference to a duct. `++duct` in
223−hoon.hoon is a list of `wire`s, where `++wire` is an alias for `++path`.
224−`++path` is a list of `++knot`s, which are ASCII text. Thus, a duct is a
225−list of paths, and a bone is an opaque reference to it (in the same way
226−that a Unix file descriptor is an opaque reference to a file structure).
227−Thus, to truly understand bones, we must understand ducts.
228−
229−A duct is stack of causes, again, represented as paths, which are called
230−wires. At the bottom of every duct is a unix event, such as a keystroke,
231−network packet, file change, or timer event. When Arvo is given this
232−event, it routes the event to appropriate kernel module for handling.
233−
234−Sometimes, the module can immediately handle the event and produce any
235−necessary results. For example, when we poked the `++poke-atom` arm
236−above, we poked %gall, our application server, which was able to respond
237−to our poke directly. When the module cannot service the request itself,
238−it sends instructions to another kernel module or application (through the
239−%gall module) to do a specified action, and produces the result from
240−that.
242+If you look up `++bone` in `hoon.hoon`, you'll see that it's a number (`@ud`),
243+and that it's an opaque reference to a duct. `++duct` in `hoon.hoon` is a list
244+of `wire`s, where `++wire` is an alias for `++path`. `++path` is a list of
245+`++knot`s, which are ASCII text. Thus, a duct is a list of paths, and a bone is
246+an opaque reference to it (in the same way that a Unix file descriptor is an
247+opaque reference to a file structure). Thus, to truly understand bones, we must
248+understand ducts.
249+
250+A duct is a stack of causes, again, represented as paths, which are called wires.
251+At the bottom of every duct is a unix event, such as a keystroke, network
252+packet, file change, or timer event. When Arvo is given this event, it routes
253+the event to appropriate kernel module for handling.
254+
255+Sometimes, the module can immediately handle the event and produce any necessary
256+results. For example, when we poked the `++poke-atom` arm above, we poked %gall,
257+our application server, which was able to respond to our poke directly. When the
258+module cannot service the request itself, it sends instructions to another
259+kernel module or application (through the %gall module) to do a specified
260+action, and produces the result from that.
241261
242262Furthermore, 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
244−tacked onto the end. Now the duct has two entries, with the unix event on
245−the bottom and the kernel module that handled it next. This process can
246−continue indefinitely, adding more and more layers onto the duct. When
247−an entity finally produces a result, a layer is popped off the duct, and
248−the result is passed all the way back down.
249−
250−In effect, a duct is an Arvo-level call stack. It's worth noting that
251−while in traditional call stacks a function call happens synchronously
252−and returns exactly once. In Arvo, multiple moves can be sent at once,
253−are evaluated asynchronously, and each one may be responded to zero or
254−more times.
255−
256−The point to take home is that whatever caused `++poke-urbit` to be
257−called is also the root cause for the network message we're trying to
258−send. Thus, we say to send the network message along the given bone
259−`ost`.
260−
261−##### Wire ('tack on new layer to duct')
262−
263−Of course, we have to push a new layer onto our duct before passing it
264−along (or responding to it directly) anywhere. This layer can have any
265−data we want in it, but we don't need anything specific here, so we just
266−use the wire `/sending` (`/elem1/elem2/elemN` is one syntax used to
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`
269−wire, meaning that the path `/sending` will be passed back to the
270−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
272−purposes.
263+application, it also sends along the duct it was given with its new wire tacked
264+onto the top. Now the duct has two entries, with the unix event on the bottom
265+and the kernel module that handled it on top. This process can continue
266+indefinitely, pushing more and more wires onto the top of the duct. When an
267+entity finally produces a result, a wire is popped off the duct, and the result
268+is passed all the way back down, repeating the process of wire popping
269+sequentially until the bottom of the duct is reached.
270+
271+In effect, a duct is an Arvo-level call stack. It's worth noting that while in
272+traditional call stacks a function call happens synchronously and returns
273+exactly once. In Arvo, multiple moves can be sent at once, are evaluated
274+asynchronously, and each one may be responded to zero or more times.
275+
276+The point to take home is that whatever caused `++poke-urbit` to be called is
277+also the root cause for the network message we're trying to send. Thus, we say
278+to send the network message along the given bone `ost`.
279+
280+##### Wire (path)
281+
282+Of course, we have to push a new wire onto our duct before passing it along (or
283+responding to it directly) anywhere. This wire can have any data we want in it,
284+but we don't need anything specific here, so we just use the wire `/sending`
285+(`/elem1/elem2/elemN` is one syntax used to create `++path`s and `++wire`s of N
286+elements). If we were expecting a response (which we're not), it would come back
287+along the `/sending` wire, meaning that the path `/sending` will be passed back
288+to the response handler as an argument. Although it's not required, it's
289+generally a good idea to make the wire human-readable for bug-handling purposes.
273290
274291##### Term (sys-call)
275292
276−Each move also has a `term`, composed of lowercase ASCII and/or `-`.
277−This `term` has the sign `@tas`. In this case, out `term` is `%poke`,
278−which is the name of the particular kind of move we're sending. You can
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
281−`%them`, to send an http request.
293+Each move also has a `term`, composed of lowercase ASCII and/or `-`. This `term`
294+has the sign `@tas`. In this case, our `term` is `%poke`, which is the name of
295+the particular kind of move we're sending. You can always use `%poke` to message
296+an app. Other common names include `%warp`, to read from the filesystem;
297+`%wait`, to set a timer; and `%them`, to send an http request.
282298
283299The 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
285−app) and marked data, then pokes the arm of the corresponding mark on
286−that app on that urbit with that data. `[to-urbit-address %pong]` is the
287−target urbit and app, `%atom` is the `mark`, and`'howdy'` is the data.
300+different data. In our case, a `%poke` move takes a target (urbit and app) and
301+marked data, then pokes the arm of the corresponding mark on that app on that
302+urbit with that data. `[to-urbit-address %pong]` is the target urbit and app,
303+`%atom` is the `mark`, and`'Pong'` is the data.
288304
289305When Arvo receives a `%poke` move, it calls the appropriate `++poke`.
290306The 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.
300316- Extend either of the apps in the first two exercises to accept input
301317 over the network in the same way as `pong`.
302318
303−- Modify `examples-pong` to print out a message when it receives
319+- Modify `pong.hoon` to print out a message when it receives
304320 acknowledgement.
305321
306322- 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
88State
99=====
1010
11−In the last section we built a few small apps that sent moves. These
12−apps were entirely stateless, however. Most useful apps require some
13−amount of state. Let's build a trivial stateful app. It'll keep a
14−running the sum of all the atoms we poke it with. Here's
15−`app/examples/sum.hoon`:
16−
17− /? 314
11+In the last section we built a few small apps that sent moves. These apps were
12+entirely stateless, however. Most useful apps require some amount of state.
13+Let's build a trivial stateful app. It'll keep a running the sum of all the
14+atoms we poke it with. Here's `examples/app/sum.hoon`:
15+
16+ :: Keeps track of the sum of all the atoms it has been
17+ :: poked with and prints the sum out
18+ ::
19+ :::: /===/app/sum/hoon
20+ ::
1821 !:
19− |_ {bowl state/@}
20− ++ poke-atom
21− |= arg/@
22− ^- {(list) _+>.$}
23− ~& [%so-far (add state arg)]
24− [~ +>.$(state (add state arg))]
22+ |%
23+ ++ move {bone card}
24+ ++ card $% $~
25+ ==
26+ --
27+ |_ {bow/bowl sum/@}
28+ ::
29+ ++ poke-atom
30+ |= tom/@
31+ ^- {(list move) _+>.$}
32+ ~& sum+(add sum tom)
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+ ::
2545 --
2646
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:
2848
29− ~fintud-macrep:dojo> :examples-sum &atom 5
30− [%so-far 5]
49+ ~fintud-macrep:dojo> :sum &atom 5
50+ [%sum 5]
3151 >=
32− ~fintud-macrep:dojo> :examples-sum &atom 2
33− [%so-far 7]
52+ ~fintud-macrep:dojo> :sum &atom 2
53+ [%sum 7]
3454 >=
35− ~fintud-macrep:dojo> :examples-sum &atom 15
36− [%so-far 22]
55+ ~fintud-macrep:dojo> :sum &atom 15
56+ [%sum 22]
3757 >=
3858
3959We can see that app state is being saved, but when, where, and how?
4060
41−The state is stored as the second thing in the `|_` line. In our case,
42−it's simply an atom named `state`. We change it by producing our
43−state not with `+>.$` (as before), but with
44−`+>.$(state (add state arg))`. We've seen all these parts before, but
45−you might not recognize them.
61+The state is stored as the second thing in the `|_` line. In our case, it's
62+simply an atom named `sum`. We change it by producing our state not with
63+`+>.$` (as before), but with `+>.$(sum (add sum tom))`. We've seen all these
64+parts before, but you might not recognize them.
4665
4766Recall in the first chapter that we recursed with the expression
48−`$(b (add 3 b))`. This meant "produce `$` with `b` changed to
49−`(add 3 b)`. Similarly, `+>.$(state (add state arg))` means "produce
50−`+>.$` (i.e. our context, which contains our state) with `state` changed
51−to `(add state arg)`.
52−
53−At a high level, then, when we handle state, we do it explicitly. It's
54−passed in and produced explicitly. In Unix systems, application state is
55−just a block of memory, which you need to serialize to disk if you want
56−to keep it around for very long.
57−
58−In Urbit, app state is a single (usually complex) value. In our example,
59−we have very simple state, so we defined `state/@`, meaning that our
60−state is an atom. Of course, `state` is just a name, and you're free to
61−name your state whatever you like. But let's clarify a couple other
62−things before we continue.
63−
64−First, `bowl` is a set of general global states. This set is managed by
65−the system. It includes things like `now` (the current time), `our` (our
66−urbit identity), and `eny` (256 bits of guaranteed-fresh entropy). For
67−the full list of things in `++bowl`, search for `++ bowl` (note: two
68−spaces) in `/arvo/zuse.hoon`.
69−
70−> This is, perhaps, the most common way to learn Hoon. The easiest way
71−> to learn about an identifier you see in code is to search in
72−> `/arvo/zuse.hoon` and `/arvo/hoon.hoon` for it.\
73−> These "standard libraries" are usually simple to read. Since Urbit's
74−> codebase is less than 15000 lines of code combined, including the hoon
75−> parser, the compiler, and the `/arvo` microkernel, you can usually use
76−> the code and its comments as a reference doc.
67+`$(b (add 3 b))`. This meant "produce `$` with `b` changed to `(add 3 b)`.
68+Similarly, `+>.$(sum (add sum tom))` means "produce `+>.$` (i.e. our
69+context, which contains our state) with `sum` changed to `(add sum tom)`.
70+
71+At a high level, then, when we handle state, we do it explicitly. It's passed in
72+and produced explicitly. In Unix systems, application state is just a block of
73+memory, which you need to serialize to disk if you want to keep it around for
74+very long.
75+
76+In Urbit, app state is a single (usually complex) value. In our example, we have
77+very simple state, so we defined `sum/@`, meaning that our state is an atom.
78+Of course, `sum` is just a name, and you're free to name your state whatever
79+you like. But let's clarify a couple other things before we continue.
80+
81+First, `bowl` is a set of general global states. This set is managed by the
82+system. It includes things like `now` (the current time), `our` (our urbit
83+identity), and `eny` (256 bits of guaranteed-fresh entropy). For the full list
84+of things in `++bowl`, search for `++ bowl` (note: two spaces) in
85+`/arvo/zuse.hoon`.
86+
87+> This is, perhaps, the most common way to learn Hoon. The easiest way to learn
88+> about an identifier you see in code is to search in `/arvo/zuse.hoon` and
89+> `/arvo/hoon.hoon` for it.\\ These "standard libraries" are usually simple to
90+> read. Since Urbit's codebase is less than 15000 lines of code combined,
91+> including the hoon parser, the compiler, and the `/arvo` microkernel, you can
92+> usually use the code and its comments as a reference doc.
7793>
7894> You can also read
79−> [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon)
80−> and
81−> [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon)
82−> in your browser.
83−
84−The second thing we should clear up is this: Urbit needs no "serialize
85−to disk" step. Everything you produce in the app state is persistent
86−across calls to the app, restarts of the urbit, and even power failure.
87−If you want to write to the Unix filesystem, you can, but it's not
88−needed for persistence. Urbit has transactional events, which makes it
89−an [ACID operating system](https://en.wikipedia.org/wiki/ACID). Thus,
90−you don't have to worry about persistence when programming in Urbit, or
91−ever go through the hassle of having to set up and write to a database.
95+> [zuse.hoon](https://github.com/urbit/arvo/blob/master/arvo/zuse.hoon) and
96+> [hoon.hoon](https://github.com/urbit/arvo/blob/master/arvo/hoon.hoon) in your
97+> browser.
98+
99+The second thing we should clear up is this: Urbit needs no "serialize to disk"
100+step. Everything you produce in the app state is persistent across calls to the
101+app, restarts of the urbit, and even power failure. If you want to write to the
102+Unix filesystem, you can, but it's not needed for persistence. Urbit has
103+transactional events, which makes it an [ACID operating
104+system](https://en.wikipedia.org/wiki/ACID). Thus, you don't have to worry about
105+persistence when programming in Urbit, or ever go through the hassle of having
106+to set up and write to a database.
92107
93108**Exercises**:
94109
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.
96111
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.
98113 Sample output:
99114
100−```
101−~fintud-macrep:dojo> :examples-last 7
102−[%last 0]
103−>=
104−~fintud-macrep:dojo> :examples-last [1 2 3]
105−[%last 7]
106−>=
107−~fintud-macrep:dojo> :examples-last 'howdy'
108−[%last [1 2 3]]
109−```
115+<!-- -->
116+
117+ ~fintud-macrep:dojo> :last 7
118+ [%last 0]
119+ >=
120+ ~fintud-macrep:dojo> :last [1 2 3]
121+ [%last 7]
122+ >=
123+ ~fintud-macrep:dojo> :last 'howdy'
124+ [%last [1 2 3]]
docs/arvo/subscriptions.md+218−140
@@ -13,62 +13,124 @@ want to subscribe to updates from another app. You could build a
1313subscription model out of one-way pokes, but it's such a common pattern
1414that it's built into arvo.
1515
16−Let's take a look at two apps, `:examples-source` and `:examples-sink`.
17−First, `:examples-source`:
18−
19− /? 314
16+Let's take a look at two apps, `:source` and `:sink`. First,
17+`:source`:
18+
19+ :: Sends subscription updates to sink.hoon
20+ ::
21+ :::: /===/app/source/hoon
22+ ::
2023 !:
24+ ::
2125 |%
22− ++ move {bone $diff mark *}
26+ ++ move {bone card}
27+ ++ card $% {$diff diff-contents}
28+ ==
29+ ++ diff-contents $% {$noun *}
30+ ==
2331 --
24− |_ {hid/bowl state/$~}
25− ++ poke-noun
26− |= arg/*
32+ ::
33+ |_ {bow/bowl $~}
34+ ::
35+ ++ poke-noun
36+ |= non/*
2737 ^- {(list move) _+>.$}
2838 :_ +>.$
29− %+ turn (prey /example-path hid)
30− |=({o/bone *} `move`[o %diff %noun arg])
31− ++ peer-example-path
39+ %+ turn (prey /example-path bow)
40+ |=({o/bone *} [o %diff %noun non])
41+ ::
42+ ++ peer-example-path
3243 |= pax/path
3344 ^- {(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
3567 [~ +>.$]
68+ ::
3669 --
3770
38−And secondly, `:examples-sink`:
39−
40− /? 314
71+And secondly, `:sink`:
72+
73+ :: Sets up a simple subscription to source.hoon
74+ ::
75+ :::: /===/app/sink/hoon
76+ ::
77+ !:
4178 |%
42− ++ move {bone card}
43− ++ card
44− $% {$peer wire {@p term} path}
45− {$pull wire {@p term} $~}
46− ==
79+ ++ move {bone card}
80+ ++ card $% {$peer wire dock path}
81+ {$pull wire dock $~}
82+ ==
4783 --
48− !:
49− |_ {bowl available/?}
50− ++ poke-noun
51− |= arg/*
84+ ::
85+ |_ {bow/bowl val/?}
86+ ::
87+ ++ poke-noun
88+ |= non/*
5289 ^- {(list move) _+>.$}
53− ?: &(=(%on arg) available)
54− [[[ost %peer /subscribe [our %source] /example-path] ~] +>.$(available |)]
55− ?: &(=(%off arg) !available)
56− [[[ost %pull /subscribe [our %source] ~] ~] +>.$(available &)]
57− ~& ?:(available %not-subscribed %subscribed)
90+ ?: &(=(%on non) val)
91+ :_ +>.$(val |)
92+ :~ :* ost.bow
93+ %peer
94+ /subscribe
95+ [our.bow %source]
96+ /example-path
97+ ==
98+ ==
99+ ?: &(=(%off non) !val)
100+ :_ +>.$(val &)
101+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
102+ ~& ?: val
103+ sink+unsubscribed+'You are now unsubscribed!'
104+ sink+subscribed+'You are now subscribed!'
58105 [~ +>.$]
59− ++ diff-noun
60− |= {wir/wire arg/*}
106+ ::
107+ ++ diff-noun
108+ |= {wir/wire non/*}
61109 ^- {(list move) _+>.$}
62− ~& [%received-data arg]
110+ ~& sink+received-data+'You got something!'
111+ ~& sink+data+non
63112 [~ +>.$]
64− ++ reap
65− |= {wir/wire error/(unit tang)}
113+ ::
114+ ++ coup
115+ |= {wir/wire err/(unit tang)}
66116 ^- {(list move) _+>.$}
67− ?~ error
68− ~& %successfully-subscribed
69− [~ +>.$]
70− ~& [%subscription-failed error]
117+ ?~ err
118+ ~& sink+success+'Poke succeeded!'
119+ [~ +>.$]
120+ ~& sink+error+'Poke failed. Error:'
121+ ~& sink+error+err
71122 [~ +>.$]
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+ ::
72134 --
73135
74136Cheat sheet:
@@ -120,41 +182,43 @@ Cheat sheet:
120182
121183Here's some sample output of the two working together:
122184
123−
124− ~fintud-macrep:dojo> |start %examples-source
185+ ~fintud-macrep:dojo> |start %source
125186 >=
126− ~fintud-macrep:dojo> |start %examples-sink
187+ ~fintud-macrep:dojo> |start %sink
127188 >=
128− ~fintud-macrep:dojo> :examples-sink %on
129− [%subscribed-to pax=/example-path]
130− %successfully-subscribed]
189+ ~fintud-macrep:dojo> :sink %on
190+ [%source %peer-notify 'Someone subscribed to you!']
191+ [%source [%ship ~fintud-macrep] %path /]
192+ [%sink %success 'Peer succeeded!']
131193 >=
132− ~fintud-macrep:dojo> :examples-source 5
133− [%received-data 5]
194+ ~fintud-macrep:dojo> :source 5
195+ [%sink %received-data 'You got something!']
196+ [%sink %data 5]
134197 >=
135− ~fintud-macrep:dojo> :examples-sink %off
198+ ~fintud-macrep:dojo> :sink %off
136199 >=
137− ~fintud-macrep:dojo> :examples-source 6
200+ ~fintud-macrep:dojo> :source 6
138201 >=
139− ~fintud-macrep:dojo> :examples-sink %on
140− [%subscribed-to pax=/example-path]
141− %successfully-subscribed]
202+ ~fintud-macrep:dojo> :sink %on
203+ [%source %peer-notify 'Someone subscribed to you!']
204+ [%source [%ship ~fintud-macrep] %path /]
205+ [%sink %success 'Peer succeeded!']
142206 >=
143− ~fintud-macrep:dojo> :examples-source 7
144− [%received-data 7]
207+ ~fintud-macrep:dojo> :source 7
208+ [%sink %received-data 'You got something!']
209+ [%sink %data 7]
145210 >=
146211
147−### :examples-source
212+### :source
148213
149214Hopefully you can get a sense for what's happening here. When we poke
150−`:examples-sink` with `%on`, `:examples-sink` subscribes to
151−`:examples-source`, and so whenever we poke `:examples-source`,
152−`:examples-sink` gets the update and prints it out. Then we unsubscribe
153−by poking `:examples-sink` with `%off`, and `:examples-sink` stops
154−getting updates. We then resubscribe.
215+`:sink` with `%on`, `:sink` subscribes to `:source`,
216+and so whenever we poke `:source`, `:sink` gets the update and
217+prints it out. Then we unsubscribe by poking `:sink` with `%off`, and
218+`:sink` stops getting updates. We then resubscribe.
155219
156−There's a fair bit going on in this code. Let's look at
157−`:examples-source` first.
220+There's a fair bit going on in this code. Let's look at `:source`
221+first.
158222
159223Our definition of `move` is fairly specific, since we're only going to
160224sending 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
167231added to it. This is why no wire is needed for the move -- we won't
168232receive anything in response to it.
169233
170−Anyways, there're two functions inside the `|_`. We already know when
171−`++poke-noun` is called. `++peer` is called when someone tries to
172−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
174−`++peer`.
175−
176−In our case, we don't care what path you subscribed on, and all we do is
177−print out that you subscribed. Arvo keeps track of your subscriptions,
178−so you don't have to. You can access your subscribers by looking at
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
181−subscribed, and which path they subscribed on. If you want to
234+Anyways, there are four functions (arms) inside the `|_`. We already know when
235+`++poke-noun` is called. `++peer-example-path` is called when someone tries to
236+subscribe to our app. Of course, you don't just subscribe to an app; you
237+subscribe to a path on that app. This path comes in as the argument to `++peer`.
238+
239+In our case, we don't care what path you subscribed on, and all we do is print
240+out that you subscribed. Arvo keeps track of your subscriptions, so you don't
241+have to. You can access your subscribers by looking at `sup` in the bowl that's
242+passed in. `sup` is of type `(map bone {@p path})`, which associates bones with
243+the urbit who subscribed, and which path they subscribed on. If you want to
182244communicate with your subscribers, send them messages along their bone.
183245
184246`++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
187249the first thing in a cell is much more complicated than the second.
188250Thus, we're producing our state unchanged.
189251
190−Our list of moves is the result of a call to `++turn`. `++turn` is what
191−many languages call "map" -- it runs a function on every item in a list
192−and collects the results in a list. The list is `(prey /example-path hid)`
193−and the function is the `|=` line right after it.
252+Our list of moves is the result of a call to `++turn`. `++turn` is what many
253+languages call "map" -- it runs a function on every item in a list and collects
254+the results in a list. The list is `(prey /example-path bow)` and the function
255+is the `|=` line right after it.
194256
195−`++prey` is a standard library function defined in `zuse`. It takes a
196−path and a bowl and gives you a list of the subscribers who are
197−subscribed on a path that begins with the given path. "Prey" is short
198−for "prefix".
257+`++prey` is a standard library function defined in `zuse.hoon`. It takes a path
258+and a bowl and gives you a list of the subscribers who are subscribed on a path
259+that begins with the given path. "Prey" is short for "prefix".
199260
200261Now 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,
202−because we don't need to know their urbit or what exact path they
203−subscribed on. Thus, our transformer function takes `{o/bone *}` and
204−produces `[o %diff %noun arg]`, which is a move that provides bone `o`
205−with this subscription update: `[%noun arg]`". This is fairly dense
206−code, but what it's doing is straightforward.
207−
208−### :examples-sink
209−
210−`:examples-source` should now make sense. `:examples-sink` is a little
211−longer, but not much more complicated.
212−
213−In `:examples-sink`, our definition of of `++move` is different. All
214−moves start with a `bone`, and we conventionally refer to the second
215−half as the "card", so that we can say a move is an action that sends a
216−card along a bone.
217−
218−We have two kinds of cards here: we `%peer` to start a subscription, and
219−we `%pull` to stop it. Both of these are "forward" moves that may
220−receive a response, so they need a wire to tack onto the duct before
221−they pass it on. They also need a target, which is a pair of an urbit
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
224−cancel any subscriptions coming over this duct. If your bone and wire
225−are the same as when you subscribed, then the cancellation will happen
226−correctly.
227−
228−The only state we need for `:examples-sink` is a boolean to indicate
229−whether we're already subscribed to `:examples-source`. We use
230−`available/?`, where `?` is the sign of type boolean (similar to `*`,
231−`@`), which defaults to true (that is, `0`).
262+`{bone @p path}`, where the only thing we really need is the bone, because we
263+don't need to know their urbit or what exact path they subscribed on. Thus, our
264+transformer function takes `{o/bone *}` and produces `[o %diff %noun non]`,
265+which is a move that provides bone `o` with this subscription update:
266+`[%noun non]`". This is fairly dense code, but what it's doing is
267+straightforward!
268+
269+### :sink
270+
271+`:source` should now make sense. `:sink` is a little longer, but not much more
272+complicated.
273+
274+In `:sink`, our definition of of `++move` is different. All moves start
275+with a `bone`, and we conventionally refer to the second half as the "card", so
276+that we can say a move is an action that sends a card along a bone.
277+
278+We have two kinds of cards here: we `%peer` to start a subscription, and we
279+`%pull` to stop it. Both of these are "forward" moves that may receive a
280+response, so they need a wire to tack onto the duct before they pass it on. They
281+also need a target, which is a pair of an urbit and an app name. Additionally,
282+`%peer` needs a path on that app to subscribe too. `%pull` doesn't need this,
283+because its semantics are to cancel any subscriptions coming over this duct. If
284+your bone and wire are the same as when you subscribed, then the cancellation
285+will happen correctly.
286+
287+The only state we need for `:sink` is a boolean to indicate whether
288+we're already subscribed to `:source`. We use `val/?`, where `?`
289+is the sign of type boolean (similar to `*`, `@`), which defaults to true (that
290+is, `0`).
232291
233292In `++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
235−`:examples-source`:
236−
237− [ost %peer /subscribe [our %source] /example-path]
238−
239−Also, we set available to false (`|`) with `+>.$(available |)`.
240−
241−Otherwise, if our input is `%off` and we're already subscribed (i.e.
242−`available` is false), then we unsubscribe from `:examples-source`:
243−
244− [ost %pull /subscribe [our %source] ~]
293+available (`val` is true). If so, we produce the move to subscribe to
294+`:source`:
295+
296+ :~ :* ost.bow
297+ %peer
298+ /subscribe
299+ [our.bow %source]
300+ /example-path
301+ ==
302+ ==
303+
304+Also, in the preceding lines, we set `val` to false (`|`) with `+>.$(val |)`.
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+
311+Otherwise, if our input is `%off` and we're already subscribed (i.e. `val`
312+is false), then we unsubscribe from `:source` and set `val` back to true (`&`),
313+again using our handy inverted cell constructor mold `:_`:
314+
315+ :_ +>.$(val &)
316+ ~[[ost.bow %pull /subscribe [our.bow %source] ~]]
245317
246318It's important to send over the same bone and wire (`/subscribe`) as the
247319one we originally subscribed on.
248320
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+ [~ +>.$]
250329
251−If neither of these cases are true, then we print our current
252−subscription state.
330+`++diff-noun` is called when we get a `%diff` update along a subscription with a
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:
253334
254−`++diff-noun` is called when we get a `%diff` update along a
255−subscription with a mark of `noun`. `++diff-noun` is given the wire that
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.
335+ ~& sink+received-data+'You got something!'
336+ ~& sink+data+non
258337
259338`++reap` is called when we receive an acknowledgment as to whether the
260−subscription was handled successfully. You can remember that `++reap` is
261−the counterpart to `++peer` as it's pronounced like 'peer' backwards.
262−Similarly, `coup` is similar to 'poke' backwards.
263−
264−Moving forward, `++reap` is given the wire we attempted to subscribe
265−over, possibly along with an error message in cases of failure.
266−`(unit type)` means "either `~` or `[~ type]`, which means it's used
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
269−print out the error message.
339+subscription was handled successfully. You can remember that `++reap` is the
340+counterpart to `++peer` as it's pronounced like 'peer' backwards. Similarly,
341+`coup` is similar to 'poke' backwards.
342+
343+Moving forward, `++reap` is given the wire we attempted to subscribe over,
344+possibly along with an error message in cases of failure. `(unit type)` means
345+"either `~` or `[~ type]`, which means it's used like Haskell's "maybe" or C's
346+nullability. If `err` is `~`, then the subscription was successful and we tell
347+that to the user. Otherwise, we print out the error message.