@@ -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.
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`:
18 :: Accepts any noun from dojo and prints it out
18 :: Accepts any noun from dojo and prints it out
20− :::: /hoon/echo/examples/app
20+ :::: /===/app/echo/hoon
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
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
37− ~fintud-macrep:dojo> |start %examples-echo
42+ ~fintud-macrep:dojo> |start %echo
40− ~fintud-macrep:dojo> :examples-echo 5
44+ ~fintud-macrep:dojo> :echo 5
41− [%argument 5]
45+ [%echo %noun 5]
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]]
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.
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`.
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)]`).
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.
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
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).
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.
88− /? 314
91+ :: Accepts an atom from the dojo and squares it.
93+ :::: /===/app/square/hoon
96+ |% ::> no moves in :square
97+ ++ move {bone card} ::> no cards in :square
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+ [~ +>.$]
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`.
104Intro to marks
114Intro to marks
105==============
115==============
@@ -124,9 +134,9 @@ using `&[mark]`. Try the following commands:
125 ~fintud-macrep:dojo> |start %square
135 ~fintud-macrep:dojo> |start %square
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]
@@ -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==================================
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`:
148− /? 314
158+ :: Allows one urbit to send the string 'Pong' to
161+ :::: /===/app/pong/hoon
150− ++ move {bone term wire *}
165+ ++ move {bone card}
166+ ++ card $% {$poke wire dock poke-contents}
168+ ++ poke-contents $% {$atom @}
152− !:
171+ |_ {bow/bowl $~} ::< stateless
155 ++ poke-urbit
173 ++ poke-urbit
156− |= to/@p
174+ |= to/ship
157 ^- {(list move) _+>.$}
175 ^- {(list move) _+>.$}
176+ ~& pong+'Outgoing pong!'
158− [[[ost %poke /sending [to dap] %atom 'howdy'] ~] +>.$]
178+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong']]
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
166 ++ coup |=(* [~ +>.$])
187 ++ coup |=(* [~ +>.$])
169Run it with these commands:
191Run it with these commands:
171− ~fintud-macrep:dojo> |start %examples-pong
193+ ~fintud-macrep:dojo> |start %pong
173− ~fintud-macrep:dojo> :examples-pong &urbit ~sampel-sipnym
195+ ~fintud-macrep:dojo> :pong &urbit ~sampel-sipnym
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:
182− [%receiving 'howdy']
204+ [%pong 'Incoming pong!']
183−
205+ [%pong %received 'Pong']
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.
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").
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:
207− [ost %poke /sending [to-urbit-address %pong] %atom 'howdy']
228+ ~[[ost.bow %poke /sending [to dap.bow] %atom 'Pong]]
@@ -218,73 +239,68 @@ Let's walk through each of these elements step by step.
219#### Bones ("cause")
240#### Bones ("cause")
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.
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.
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.
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.
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.
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`.
260−
280+##### Wire (path)
261−##### Wire ('tack on new layer to duct')
281+
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.
274##### Term (sys-call)
291##### Term (sys-call)
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.
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.
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`.
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.
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`,