on master help sign in
151ization & rendering complete
commit932d39157980e050563b911d53dd6ffc8429667f authorHenry Ault <henry@tlon.io> dateWed 13 Apr 2016, 16:41 (11 years ago) parent65048fe
9 files changed+219−124
docs/programming/system/basic.md+20−15 docs/programming/system/generators.md+116−43 docs/programming/system/http.md+32−20 docs/programming/system/marks.md+2−2 docs/programming/system/network.md+8−12 docs/programming/system/state.md+14−12 docs/programming/system/subject.md+8−2 docs/programming/system/subscriptions.md+2−5 docs/programming/system/web-apps.md+17−13
docs/programming/system/basic.md+20−15
@@ -14,7 +14,7 @@ glance, read it over again.
1414
1515Our goal is to get you programming interesting and useful things
1616as soon as possible. To get there, we have to quickly cover some
17−of the fundamentals of hoon. To do this we'll walk through two
17+of the fundamentals of hoon. To do this, we'll walk through two
1818simple programs: the first [Project
1919Euler](https://projecteuler.net/) problem and
2020[fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
@@ -66,7 +66,6 @@ under `/examples/gen/euler1.hoon`):
6666
6767```
6868:: project euler 1
69−:: project euler 1
7069:: https://projecteuler.net/problem=1
7170:: run in dojo with +euler1
7271::
@@ -103,14 +102,16 @@ under `/examples/gen/euler1.hoon`):
103102--
104103```
105104
106−<blockquote class=“blockquote”>
107−> Hoon is not generally whitespace sensitive, but we do have two
108−> different kinds of whitespace: a single space and a gap, which
109−> is two or more spaces or a linebreak. Tabs are taboo. Do not
110−> use them. Really. For a more detailed explanation of when to
111−> use spaces vs. gaps, see the syntax section before the first
112−> excercises.
113−<blockquote class=“blockquote”>
105+
106+<blockquote class="blockquote">
107+Hoon is not generally whitespace sensitive, but we do have two
108+different kinds of whitespace: a single space and a gap, which
109+is two or more spaces or a linebreak. Tabs are taboo. Do not
110+use them. Really. For a more detailed explanation of when to
111+use spaces vs. gaps, see the [syntax section](docs/programming/core/twig/syntax) before the first
112+excercises.
113+</blockquote>
114+
114115
115116### Lines 1-11:
116117
@@ -126,7 +127,7 @@ more detail later.
126127
127128### How to form expressions
128129
129−Hoon does not use reserved words to form expressions. (We did recently implement an alternative keyword syntax, which is not covered here. For more information, see the [syntax section]()). Instead,
130+Hoon does not use reserved words to form expressions. (We did recently implement an alternative keyword syntax, which is not covered here. For more information, see the [syntax section](docs/programming/core/twig/syntax)). Instead,
130131expressions are formed with runes--diagraphs of two
131132ascii symbols. Each rune takes a specific number of
132133children--either expressions formed by other runes or literals
@@ -177,8 +178,10 @@ element in this map begins with a `++` followed by the name and
177178the corresponding code. Since `|%` takes an arbitrary number of
178179children, it needs to be closed with a `--`.
179180
180−> `++` is not technically a rune, since it is only used in core
181−> syntax as shown above
181+<blockquote class="blockquote">
182+`++` is not technically a rune, since it is only used in core
183+syntax as shown above
184+</blockquote>
182185
183186Let's step into each of the three arms within our core.
184187
@@ -242,8 +245,10 @@ Note that we only specify what changes (`b` in this case). If
242245you recurse by an actual function call, then you have to specify
243246every argument.
244247
245−> If you're familiar with Clojure, `|-` is `loop` and `$()` is
246−> recur.
248+<blockquote class="blockquote">
249+If you're familiar with Clojure, `|-` is `loop` and `$()` is
250+recur.
251+</blockquote>
247252
248253**Exercises**:
249254
docs/programming/system/generators.md+116−43
@@ -1,6 +1,6 @@
11---
22next: true
3−sort: 7
3+sort: 8
44title: Using Generators with Apps
55---
66
@@ -12,7 +12,7 @@ the "plumbing" way to interact with apps. Generators are the
1212`|merge`, there are no marks in sight.
1313
1414We've used generators before, back in [Basic
15−Operation](basic). At that point, we just used the generators
15+Operation](http://urbit.org/docs/user/basic). At that point, we just used the generators
1616to produce values -- we didn't pipe their results into apps. In
1717the dojo cast, the role of a generator is to take a list of
1818arguments and produce a value, which is often, though not always,
@@ -52,10 +52,8 @@ abbreviated to `:my-app|my-generator <args>`. Because most
5252built-in commands are generators for the `:hood` app,
5353`:hood|generator <args>` can be shortened to `|generator <args>`.
5454
55−XXThe paragraph above is too long and confusing
56−
5755Let's write a generator for a modified version of `:pong` from
58−the chapter on [Network Messages](network). Recall that `:pong`
56+the chapter on [Network Messages](http://urbit.org/docs/user/network). Recall that `:pong`
5957takes an urbit address, which is of mark `urbit`, and sends that
6058urbit the message `'howdy'`. First--without a generator--let's
6159make `:ping` that does the same, except that it lets the user
@@ -64,44 +62,117 @@ optionally specify the message as well.
6462We'll need a new mark for our arguments. Let's call it
6563`ping-message`.
6664
67−> For app-specific marks, it's good style to prefix the name of
68−> the mark with the name of the app. Since many apps have
69−> several such marks, subdirectories in `/mar` are rendered as
70−> `-`, so that `ping-message` is written in
71−> (`/mar/ping/message.hoon`).
65+<blockquote class="blockquote">
66+For app-specific marks, it's good style to prefix the name of
67+the mark with the name of the app. Since many apps have
68+several such marks, subdirectories in `/mar` are rendered as
69+`-`, so that `ping-message` is written in
70+(`/mar/ping/message.hoon`).
71+</blockquote>
7272
7373```
74−|_ [to=@p message=@t]
75−++ grab
76− |%
77− ++ noun ,[@p @t]
78− --
74+:: Up-ness monitor. Accepts atom url, 'on', or 'off'
75+::
76+:::: /hoon/up/examples/app
77+ ::
78+/? 314
79+|%
80+++ move {bone card}
81+++ card
82+ $% {$hiss wire $~ $httr {$purl p/purl}}
83+ {$wait wire @da}
84+ ==
85+++ action
86+ $% {$on $~} :: enable polling('on')
87+ {$off $~} :: disable polling('off)
88+ {$target p/cord} :: set poll target('http://...')
89+ ==
90+--
91+|_ {hid/bowl on/_| in-progress/_| target/@t}
92+++ poke-atom
93+ |= url-or-command/@t ^- (quip move +>)
94+ =+ ^- act/action
95+ ?: ?=($on url-or-command) [%on ~]
96+ ?: ?=($off url-or-command) [%off ~]
97+ [%target url-or-command]
98+ ?- -.act
99+ $target [~ +>.$(target p.act)]
100+ $off [~ +>.$(on |)]
101+ $on
102+ :- ?: |(on in-progress) ~
103+ [ost.hid %hiss /request ~ %httr %purl (need (epur target))]~
104+ +>.$(on &, in-progress &)
105+ ==
106+::
107+
108+:: ~& 'i get here'
109+:: ^- {(list move) _+>.$}
110+:: ?: =('off' url)
111+:: [~ +>.$(on |)]
112+:: ?: =('on' url)
113+:: :_ +>.$(on &, in-progress &)
114+:: ?: |(on in-progress)
115+:: ~
116+:: [ost.hid %them /request ~ (need (epur target)) %get ~ ~]~
117+:: [~ +>.$(target url)]
118+++ sigh-httr
119+ |= {wir/wire code/@ud headers/mess body/(unit octs)}
120+ ~& 'arrive here'
121+ ^- {(list move) _+>.$}
122+ ?: &((gte code 200) (lth code 300))
123+ ~& [%all-is-well code]
124+ :_ +>.$
125+ [ost.hid %wait /timer (add ~s10 now.hid)]~
126+ ~& [%we-have-a-problem code]
127+ ~& [%headers headers]
128+ ~& [%body body]
129+ :_ +>.$
130+ [ost.hid %wait /timer (add ~s10 now.hid)]~
131+++ wake-timer
132+ |= {wir/wire $~} ^- (quip move +>)
133+ ?: on
134+ :_ +>.$
135+ [ost.hid %hiss /request ~ %httr %purl (need (epur target))]~
136+ [~ +>.$(in-progress |)]
137+::
138+++ prep ~& target _`. ::
79139--
80140```
81141
82−The app can easily be modified to use this (`/ape/ping.hoon`):
142+The app can easily be modified to use this (`/app/ping.hoon`):
83143
84144```
85−/? 314
145+::
146+:::: /hoon/ping/examples/app
147+ ::
148+/? 151
86149|%
87− ++ move ,[bone term wire *]
150+ ++ move {bone term wire *}
88151--
89152!:
90−|_ [bowl state=~]
153+|_ {bowl state/$~}
91154::
92−++ poke-ping-message
93− |= [to=@p message=@t]
94− ^- [(list move) _+>.$]
95− [[[ost %poke /sending [to dap] %atom message] ~] +>.$]
155+++ poke-examples-ping-message
156+ |= {to/@p message/@t}
157+ ~& 'sent'
158+ ^- {(list move) _+>.$}
159+ :- ^- (list move)
160+ :~ `move`[ost %poke /sending [to dap] %atom message]
161+ ==
162+ +>.$
96163::
97164++ poke-atom
98− |= arg=@
99− ^- [(list move) _+>.$]
100− ~& [%receiving (,@t arg)]
165+ |= arg/@
166+ ~& 'received'
167+ ^- {(list move) _+>.$}
168+ ::
169+ ~& [%receiving (@t arg)]
101170 [~ +>.$]
102171::
103172++ coup |=(* `+>)
104173--
174+
175+
105176```
106177
107178Now we can run this with:
@@ -123,11 +194,11 @@ to `:ping`, let's put it in `/gen/ping/send.hoon`:
123194
124195```
125196:- %say
126−|= [^ [[to=@p message=?(~ [text=@t ~])] ~]]
197+|= {^ {{to/@p message/?($~ {text/@t $~})} $~}
127198[%ping-message to ?~(message 'howdy' text.message)]
128199```
129200
130−A couple of new things here. Firstly, `message=?(~ [text=@t ~])`
201+A couple of new things here. Firstly, `message/?($~ {text=@t $~})`
131202should be read as "the message is either null or a pair of text
132203and null". Generator argument lists are always null-terminated,
133204which makes it convenient to accept lists in tail position (which
@@ -140,21 +211,23 @@ text and null.
140211Secondly, `?~(a b c)` is a rune which means "if the `a` is null,
141212do `b`, else `c`". It is roughly equivalent to `?:(=(~ a) b c)`.
142213
143−> `?~(a b c)` is actually equivalent to `?:=(?=(~ a) b c)`,
144−> which, although identical at run time, is subtly different at
145−> compile time. Specifically, using `?=` rather than `=` means
146−> that we're checking whether `a` is in the *type* of `~`, and so
147−> the compiler knows that in the `b` case `a` is null, and in the
148−> `c` case `a` is not null. Since `=` is purely a runtime value
149−> check with no type implications, the compiler doesn't gain any
150−> information.
151−>
152−> At any rate, this is the reason why we can refer to
153−> `text.message` in the `c` clause. The compiler knows that
154−> `message` is not null, so it must have `text` within it. If
155−> you used `?:(=(~ message) 'howdy' text.message)` the compiler
156−> would complain that it doesn't know whether `message` has
157−> `text` within it.
214+<blockquote class="blockquote">
215+`?~(a b c)` is actually equivalent to `?:=(?=(~ a) b c)`,
216+which, although identical at run time, is subtly different at
217+compile time. Specifically, using `?=` rather than `=` means
218+that we're checking whether `a` is in the *type* of `~`, and so
219+the compiler knows that in the `b` case `a` is null, and in the
220+`c` case `a` is not null. Since `=` is purely a runtime value
221+check with no type implications, the compiler doesn't gain any
222+information.
223+
224+At any rate, this is the reason why we can refer to
225+`text.message` in the `c` clause. The compiler knows that
226+`message` is not null, so it must have `text` within it. If
227+you used `?:(=(~ message) 'howdy' text.message)` the compiler
228+would complain that it doesn't know whether `message` has
229+`text` within it.
230+</blockquote>
158231
159232This is run as follows:
160233
docs/programming/system/http.md+32−20
@@ -1,9 +1,11 @@
11---
22next: false
3−sort: 8
3+sort: 9
44title: HTTP Requests and Timers
55---
66
7+# Writing an HTTP request
8+
79There's a variety of arvo services we haven't touched on yet.
810Let's figure out how to make HTTP requests and set timers.
911
@@ -63,10 +65,12 @@ line, though.
6365Firstly, there's two kinds of cards we're sending to arvo. A
6466`%them` card makes an HTTP requrest out of a unit `hiss`.
6567
66−> Recall that `++unit` means "maybe". Formally, "`(unit a)` is
67−> either null or a pair of null and a value in `a`". Also recall
68−> that to pull a value out of a unit `(u.unit)`, you must first
69−> verify that the unit is not null (for example with `?~`).
68+<blockquote class="blockquote">
69+Recall that `++unit` means "maybe". Formally, "`(unit a)` is
70+either null or a pair of null and a value in `a`". Also recall
71+that to pull a value out of a unit `(u.unit)`, you must first
72+verify that the unit is not null (for example with `?~`).
73+</blockquote>
7074
7175A `hiss` (all of the following terms are defined in `zuse`) is a
7276pair of a `purl` and a `moth`. A `purl` is a parsed url
@@ -80,9 +84,11 @@ of HTTP headers. The `(unit octs)` is a possible octet stream
8084representing the body. If it's null, then no body is sent (as in
8185this case).
8286
83−> An octect stream is a pair of the length in bytes of the data
84−> plus the data itself. You can use `++taco` takes text and
85−> turns it into an octet strem.
87+<blockquote class="blockquote">
88+An octect stream is a pair of the length in bytes of the data
89+plus the data itself. You can use `++taco` takes text and
90+turns it into an octet strem.
91+</blockquote>
8692
8793When you send this request, you can expect a `%thou` with the
8894response, which we handle later on in `++thou-request`.
@@ -90,9 +96,11 @@ response, which we handle later on in `++thou-request`.
9096For `%wait`, you just pass a [`@da`]() (absolute date), and arvo will
9197produce a `%wake` when the time comes.
9298
93−> A timer is guaranteed to not be triggered before the given
94−> time, but it's currently impossible to guarantee the timer will be
95−> triggered at exactly the requested time.
99+<blockquote class="blockquote">
100+A timer is guaranteed to not be triggered before the given
101+time, but it's currently impossible to guarantee the timer will be
102+triggered at exactly the requested time.
103+</blockquote>
96104
97105Let's take a look at our state:
98106
@@ -113,9 +121,11 @@ of `value`, but make the default value be `value`". Thus, our
113121type is still a boolean, just like `?`, but the default value is
114122`|` (false).
115123
116−> This is the same `_` used in `_+>.$`, which means "the same
117−> type as the value "+>.$". In other words, the same type as our
118−> current context and state.
124+<blockquote class="blockquote">
125+This is the same `_` used in `_+>.$`, which means "the same
126+type as the value "+>.$". In other words, the same type as our
127+current context and state.
128+</blockquote>
119129
120130Let's take a look at `++poke-cord`. When we're poked with a
121131cord, we first check whether it's `'off'`. If so, we set `on` to
@@ -129,12 +139,14 @@ This request follows the pattern in `++hiss` well. `(need (epur
129139target))` is the parsed url, `%get` is the HTTP method, `~`
130140means no extra headers, and another `~` means no body.
131141
132−> Note the `~` at the end of the move. This is a convenient
133−> shortcut for creating a list of a single element. It's part of
134−> a small family of such shortcuts. `~[a b c]` is `[a b c ~]`,
135−> `[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`.
136−> These may be mixed and matched to create various convoluted
137−> structures and emojis.
142+<blockquote class="blockquote">
143+Note the `~` at the end of the move. This is a convenient
144+shortcut for creating a list of a single element. It's part of
145+a small family of such shortcuts. `~[a b c]` is `[a b c ~]`,
146+`[a b c]~` is `[[a b c] ~]` and `\`[a b c]` is `[~ a b c]`.
147+These may be mixed and matched to create various convoluted
148+structures and emojis.
149+</blockquote>
138150
139151If the argument is neither 'off' nor 'on', then we assume it's an
140152actual url, so we save it in `target`.
docs/programming/system/marks.md+2−2
@@ -1,6 +1,6 @@
11---
22next: true
3−sort: 5
3+sort: 6
44title: Marks
55---
66
@@ -34,7 +34,7 @@ case, the argument is the marked data.
3434
3535There are three possible top-level arms in the `|_` core,
3636`++grab`, `++grow`, and `++grad`. `++grad` is used for revision
37−control, and is covered elsewhere. `++grab` specifies
37+controlv (it contains diff/patch logic), and is covered elsewhere. `++grab` specifies
3838functions to convert from another mark to the current mark.
3939`++grow` specifies how to convert from the current mark to
4040another one.
docs/programming/system/network.md+8−12
@@ -1,6 +1,6 @@
11---
22next: false
3−sort: 2
3+sort: 3
44title: Network messages
55---
66
@@ -15,7 +15,7 @@ commands that produce a value and then disappear. To listen for and receive mes
1515```
1616:: There is no love that is not an echo
1717::
18−:::: /hoon/echo/ape
18+:::: /hoon/echo/app
1919 ::
2020/? 314
2121!:
@@ -154,12 +154,6 @@ pipeline, so we'll be getting quite used to them.
154154- Write an app that computes fizzbuzz on its input (as in the
155155 previous section).
156156
157−- One way of representing strings is with double quoted strings
158− called "tapes". The hoon type is `++tape`, Write an app that
159− accepts a tape and prints out `(flop argument)`, where
160− `argument` is the input. What does this do?
161−
162−
163157# Sending a message to another ship
164158
165159Let's write our first network message! Here's `/app/pong.hoon`:
@@ -325,10 +319,12 @@ When arvo receives a `%poke` move, it calls the appropriate
325319between apps on the same urbit as for sending messages between
326320apps on different urbits.
327321
328−> We said earlier that we're not expecting a response. This is
329−> not entirely true: the `++coup` is called when we receive
330−> acknowledgment that the `++poke` was called. We don't do
331−> anything with this information right now, but we could.
322+<blockquote class="blockquote">
323+We said earlier that we're not expecting a response. This is
324+not entirely true: the `++coup` is called when we receive
325+acknowledgment that the `++poke` was called. We don't do
326+anything with this information right now, but we could.
327+</blockquote>
332328
333329**Exercises**:
334330
docs/programming/system/state.md+14−12
@@ -1,6 +1,6 @@
11---
22next: true
3−sort: 3
3+sort: 4
44title: State
55---
66
@@ -8,7 +8,7 @@ In the last section we built a few small apps that sent moves.
88These apps were entirely stateless, however. Most useful apps
99require some amount of state. Let's build a trivial stateful
1010app. It'll keep a running the sum of all the atoms we poke it with.
11−Here's `ape/sum.hoon`:
11+Here's `app/sum.hoon`:
1212
1313```
1414/? 314
@@ -69,16 +69,18 @@ identity), and `eny` (256 bits of guaranteed-fresh entropy). For
6969the full list of things in `++bowl`, search for `++ bowl` (note
7070the double space) in `/arvo/zuse.hoon`.
7171
72−> This is a very common technique in learning hoon. While
73−> documentation exists, often the easiest way to learn about an
74−> identifier you see in code is to search in `/arvo/zuse.hoon`
75−> and `/arvo/hoon.hoon` for it. These are our two "standard
76−> libraries", and they're usually not hard to read. Since
77−> urbit's codebase is relatively small (those two files are less
78−> than 15000 lines of code combined, and besides the standard
79−> library they include the hoon parser and compiler, plus the
80−> /arvo microkernel), you can usually use the code and the
81−> comments as reference doc.
72+<blockquote class="blockquote">
73+This is a very common technique in learning hoon. While
74+documentation exists, often the easiest way to learn about an
75+identifier you see in code is to search in `/arvo/zuse.hoon`
76+and `/arvo/hoon.hoon` for it. These are our two "standard
77+libraries", and they're usually not hard to read. Since
78+urbit's codebase is relatively small (those two files are less
79+than 15000 lines of code combined, and besides the standard
80+library they include the hoon parser and compiler, plus the
81+/arvo microkernel), you can usually use the code and the
82+comments as reference doc.
83+</blockquote>
8284
8385The second thing is that urbit needs no "serialize to disk" step.
8486Everything you produce in the app state is persistent across
docs/programming/system/subject.md+8−2
@@ -1,4 +1,10 @@
1−## The subject
1+---
2+sort: 2
3+next: true
4+title: Hoon refresher / crash course
5+---
6+
7+# The subject
28
39Now we're going to cover the boiler plate that we skimmed over
410earlier.
@@ -86,7 +92,7 @@ Cheatsheet:
8692
8793- To pass arguments from the command line to a program, you
8894 replace the `*` in the first line of the boiler plate to
89− `[^ [[arg=TYPE ~] ~]]` where `TYPE` is replaced with the
95+ `{^ {{arg/TYPE ~} ~}}` where `TYPE` is replaced with the
9096 type of argument you're expecting. Then `+euler1 a` from
9197 the dojo sets `arg` to `a`.
9298- The empty list is `~`
docs/programming/system/subscriptions.md+2−5
@@ -1,6 +1,6 @@
11---
22next: true
3−sort: 4
3+sort: 5
44title: Subscriptions
55---
66
@@ -111,8 +111,6 @@ Cheat sheet:
111111 the `|_`, as it lies above it: hoon.hoon `=> |% w types =>
112112 |_`
113113
114−
115−
116114
117115```
118116
@@ -202,7 +200,7 @@ Now we have the list of relevant subscribers. This a list of
202200triples, `{bone @p path}`, where the only thing we really need is
203201the bone because we don't care what urbit they are or what exact
204202path they subscribed on. Thus, our transformer function takes
205−`{o=bone *}` and produces `[o %diff %noun arg]`, which is a move
203+`{o/bone *}` and produces `[o %diff %noun arg]`, which is a move
206204that provides bone `o` with this subscription update: `[%noun
207205arg]`". This is fairly dense code, but what it's doing is
208206straightforward.
@@ -276,4 +274,3 @@ means it's used like Haskell's "maybe" or C's nullability. If
276274`error` is `~`, then the subscription was successful and we tell
277275that to the user. Otherwise, we print out the error message.
278276
279−Excercises XX
docs/programming/system/web-apps.md+17−13
@@ -1,6 +1,6 @@
11---
22next: true
3−sort: 6
3+sort: 7
44title: Web Apps
55---
66
@@ -71,16 +71,18 @@ asserting the parsing succeeded with `need`, and asserting the
7171result was 'click' with `?>`, which asserts that its first child
7272is true.
7373
74−> Note the argument to `++json`is `jon/^json`. Why `^json`?
75−> `++json` shadows the type definition, so if we want to refer to
76−> the type, we have to prepend a `^`. This extends to multiple
77−> levels: `^^^foo` means the fourth most innermost instance of `foo`.
74+<blockquote class="blockquote">
75+Note the argument to `++json`is `jon/^json`. Why `^json`?
76+`++json` shadows the type definition, so if we want to refer to
77+the type, we have to prepend a `^`. This extends to multiple
78+levels: `^^^foo` means the fourth most innermost instance of `foo`.
7879
79−> `++jo` in `zuse` is a useful library for parsing complex json
80−> into hoon structures. In this case, the `:` between `so` and
81−> `jo` means 'inside of', because `so` is an arm contained within
82−> the core `jo`. Our case is actually simple enough that the
83−> `?>` line could have been `?> =([%s 'click'] jon)`.
80+`++jo` in `zuse` is a useful library for parsing complex json
81+into hoon structures. In this case, the `:` between `so` and
82+`jo` means 'inside of', because `so` is an arm contained within
83+the core `jo`. Our case is actually simple enough that the
84+`?>` line could have been `?> =([%s 'click'] jon)`.
85+</blockquote>
8486
8587We can test this mark from the command line (don't forget to start your app with `|start %click`)
8688
@@ -112,9 +114,11 @@ And `/mar/clicks.hoon`:
112114`clicks` is just an atom. We convert to json by creating an
113115object with a single field "clicks" with our value.
114116
115−> Be sure to checkout section 3bD, JSON and XML, in zuse.hoon
116−> `++joba` is just a function that takes a key-value pair and
117−> produces a JSON object with one element.
117+<blockquote class="blockquote">
118+Be sure to checkout section 3bD, JSON and XML, in zuse.hoon
119+`++joba` is just a function that takes a key-value pair and
120+produces a JSON object with one element.
121+</blockquote>
118122
119123```
120124~fintud-macrep:dojo> &json &clicks 6