9The dojo is a typed functional shell. Assuming our default
18To print a Hoon expression or other recipe:
20 ~fintud-macrep:dojo> (add 2 2)
22To save a recipe as a variable `foo`:
24 ~fintud-macrep:dojo> =foo (add 2 2)
26To save as a unix file (`$pier/.urb/put/foo/bar.baz`):
28 ~fintud-macrep:dojo> .foo/bar/baz (add 2 2)
30To save as an urbit file (`/===/foo/bar/baz`):
32 ~fintud-macrep:dojo> *foo/bar/baz (add 2 2)
34A noun generator with ordered and named arguments:
36 ~fintud-macrep:dojo> +make one two three, =foo (add 2 2), =bar 42
38A poke message to an urbit daemon:
40 ~fintud-macrep:dojo> :~fintud-macrep/talk (add 2 2)
42A system command to `:hood`:
44 ~fintud-macrep:dojo> |reload %vane
48An Urbit value is called a "noun." A noun is either an unsigned
49integer ("atom") or an ordered pair of nouns ("cell"). Nouns
50are just values, with no cyclic structure or pointer identity.
52The dojo is your safe space for hand-to-hand combat with nouns.
53Every dojo command builds a "product" noun functionally, then
54applies this product in a side effect -- show, save, or send.
58In the quickstart we learned a crude interpretation of the dojo
59in terms of "expressions, generators and operations." While
60nothing in the quickstart section is inaccurate, it's not the way
61the system works internally.
63*All* dojo lines are commands. An operation uses a *recipe*
64to create a noun, which the command uses in its side effect.
65Just printing the noun is a trivial case of a command.
67Recipes are *conceptually* functional, but often use concrete,
68stateful action sequences. A simple Hoon expression (*twig*) is
69purely functional, but it's only one kind of recipe.
71A recipe can get data from an HTTP GET request or an interactive
72input dialog. It can also query, even block on, the Urbit
73namespace. These operations are *conceptually* functional, but
74not *actually* functional. They don't belong in a pure Hoon
75expression, but they do belong in a dojo recipe. A recipe is "FP
76in the large," more like Unix pipes than Haskell monads.
78The dojo is "single-threaded" in each session. One session can
79work on one command at a time. The session does not accept user
80input while processing a command, even when it blocks over the
81network. And each session's state is independent. (If you want
82to work on two things at a time, connect two console sessions to
85Once you've built the product of your recipe, you show, save,
88You can pretty-print the product to the console. You can save it
89-- as a dojo variable, as a revision to the Urbit filesystem, or
90as an export to a file in the Unix filesystem. Or you can
91send it -- staying native with an Urbit poke, or going retro
94All these operations are typed. Hoon is a statically typed
95language, but the dojo is a dynamic interpreter. The nouns you
96build in the dojo are dynamically typed nouns, or "cages".
98A cage actually has two layers of type: "mark," a network label
99(like a MIME type), and "span," a Hoon language type. When a
100cage is sent across the Urbit network, the receiving daemon
101validates the noun against its own version of the mark, and
104Of course, sometimes a recipe produces a noun with mark `%noun`,
105meaning "any noun," and span `*`, the set of all nouns. We have
106no choice but to do the best we can with mystery nouns, but we
107prefer a formal description.
109A mark is also called a "format." Marks let us perform a variety
110of formal typed operations on nouns: validation, translation,
111even patch and diff for revision control.
115An excellent way to understand `:dojo` is to read the source,
116which is in `/===/app/dojo/hoon` (or `home/app/dojo.hoon` if your `home` desk is mounted to Unix).
118You may or may not know Hoon. We'll use some Hoon
119snippets here for defining structures and grammars. Just think
120of it as pseudocode -- the meaning should be clear from context.
122### Syntax and semantics
124To use the dojo, type a complete command at the dojo prompt.
125The simplest command just prints a Hoon expression:
127 ~fintud-macrep:dojo> (add 2 2)
129Hit return. You'll see:
135Similarly in tall form,
137 ~fintud-macrep:dojo> %+ add 2 2
142An incomplete command goes into a multiline input buffer. Use
143the up-arrow (see the console history section) to get the last
144command back, edit it so it's just `%+ add 2`, and press return.
150Enter `2`. You'll see:
157The full command that parses and runs is the concatenation of all
158the partial lines, with a space inserted between them. To clear
159all multiline input, just hit return on an empty prompt.
163Every finished line is parsed into one `++dojo-command`:
166 $% [%edit p=path q=dojo-recipe] :: modify clay file
167 [%http p=? q=purl r=dojo-recipe] :: http post or put
168 [%poke p=goal q=dojo-recipe] :: send request
169 [%save p=path q=dojo-recipe] :: replace clay file
170 [%show p=dojo-recipe] :: print to console
171 [%unix p=path q=dojo-recipe] :: export to unix
172 [%verb p=term q=dojo-recipe] :: store variable
175Each kind of `++dojo-command` is an action that depends on one
176noun production, a `++dojo-recipe`. We describe first the
177commands, then the recipes.
179##### `[%show p=dojo-recipe]`
181To print the product, the command is just the recipe:
183 ~fintud-macrep:dojo> (add 2 2)
185##### `[%verb p=term q=dojo-recipe]`
187To save the product to a variable `foo`:
189 ~fintud-macrep:dojo> =foo (add 2 2)
191`foo` goes into your Hoon subject (scope) and is available to all
196 ~fintud-macrep:dojo> =foo
198The dojo has a set of special variables, some read-write and some
208The read-write specials are `dir`, `lib` and `arc`. `dir` is the
209current working beak (`%clay` branch and revision) and directory. The
210current beak is often the invalid "version 0", which is shorthand for
211the most recent revision. If you need a valid `%clay` path, say, as an
212argument to `+ls`, use the special read-only variable `%`, which
213automatically expands this to the current time. If `dir` is unset,
214then the current working path is defaulted to the current revision of
215the `home` desk on your urbit.
217`lib` is a set of libraries, and `arc` a set of structures, to put in
218the Hoon subject. Add libraries with the `%ford` rune `/+`, and
219structures with `/-`. Libraries will be loaded from the `lib`
220directory in the current beak, and structures from the `sur`
223Read-only specials are `now`, the current (128-bit `@da`) time, `our`,
224the current urbit, and `eny`, 256 bits of fresh entropy.
226##### `[%edit p=path q=dojo-recipe]`
227##### `[%save p=path q=dojo-recipe]`
229The product is either a new version of, or a modification to,
230the Urbit file at the given path. (See the discussion of Urbit
235 ~fintud-macrep:dojo> *%/numbers/four (add 2 2)
239 ~fintud-macrep:dojo> -%/numbers/four (add 2 2)
241A save (`*`) overwrites the current (if any) version of the file
242with a new version of any mark. The save command above will work
243(if you want `/numbers/four` at your current path).
245An edit (`-`) applies a diff whose mark has to match the diff
246mark for the current version of the file. The edit command above
247will not work, because evaluating a Hoon expression like `(add 2
2482)` just produces a `%noun` mark, ie, an arbitrary noun.
250For either saves or edits, the current version of the file must
251be the same version specified in the write -- in other words,
252we can only write to HEAD. If someone else has sneaked in a
253change since the version specified, the command will fail.
255##### `[%unix p=path q=dojo-recipe]`
257 ~fintud-macrep:dojo> ./numbers/four (add 2 2)
259The product is saved as a Unix file (its mark is translated
260to MIME, and the MIME type is mapped as the extension).
262##### `[%poke p=goal q=dojo-recipe]`
264A poke or *order* is a one-way transactional request. It either
265succeeds and returns no information, or fails and produces an
268Every order is sent to one daemon on one urbit. The default
269urbit is your urbit. The default daemon is the system daemon,
270`:hood`. The following syntactic forms are equivalent:
272 ~fintud-macrep:dojo> :~fintud-macrep/hood (add 2 2)
273 ~fintud-macrep:dojo> :hood (add 2 2)
274 ~fintud-macrep:dojo> :~fintud-macrep (add 2 2)
275 ~fintud-macrep:dojo> : (add 2 2)
277Urbit pokes do not have a separate verb. The mark of the message
278defines the semantics of the operation. You don't call a method
279`foo` whose argument is a noun in mark `bar` -- you poke a noun
280in mark `bar`. The mark is the protocol is the method.
282If the order succeeds, you'll see an `>=` line. If not, you'll
283see an error report, typically with a stack trace.
285It's common (but not necessary) to use a custom generator for the
286daemon you're talking to. (For generators, see below.) Hence
288 ~fintud-macrep:dojo> :~fintud-macrep/fish +fish/catch (add 2 2)
290It's irritating to type "fish" twice, just because we're using a
291fish generator to talk to a fish daemon. Hence a shortcut:
293 ~fintud-macrep:dojo> :~fintud-macrep/fish|catch (add 2 2)
295If we combine all these defaults, we get the "system command"
298 ~fintud-macrep:dojo> :~fintud-macrep/hood +hood/reload %ames
299 ~fintud-macrep:dojo> |reload %ames
301This is the most common poke, a generated message to your own
304##### `[%http p=? q=purl r=dojo-recipe]`
306The Web has its own poke, unfortunately in two flavors. To POST,
308 ~fintud-macrep:dojo> +http://website.com (add 2 2)
312 ~fintud-macrep:dojo> -http://website.com (add 2 2)
314As with a poke, you'll get a >= for success, or an error report.
316#### Recipes, models and filters
318But wait, what's a recipe? Simplifying the actual code slightly:
320 ++ dojo-recipe :: functional build
321 $% [%ex p=twig] :: hoon expression
322 [%as p=mark q=dojo-recipe] :: format conversion
323 [%do p=twig q=dojo-recipe] :: apply gate
324 [%ge p=dojo-script] :: generator
325 [%ur p=purl] :: get url
326 [%tu p=(list dojo-recipe)] :: tuple
328 ++ dojo-script :: script
329 $: p=path :: core recipe
330 q=dojo-config :: configuration
332 ++ dojo-config :: configuration
333 $: p=(list dojo-recipe) :: by order
334 q=(map term (unit dojo-recipe)) :: by keyword
339The twig in an `%ex` recipe is a Hoon expression. The recipe
340syntax is just the Hoon syntax.
342The subject of the twig is a core stack: first the Hoon kernel,
343then the Arvo standard library, then the structures and libraries
344in `lib` and `arc`. On the very top are the dojo variables.
346A twig produces the trivial mark `%noun`, except in two cases
347where the dojo can do better. The dojo analyzes the twig to
348detect two trivial cases where direct evaluation gives us a mark:
349a variable reference like `foo` that matches a dojo variable, or
350an urbitspace dereference like `.^(/cx/~fintud-macrep/main/1/foo)`.
351In either case, if we executed these through Hoon, we'd get the
352same noun with the same span.
354##### `[%tu p=(list dojo-recipe)]`
356A is just a tuple of recipes, using the normal Hoon syntax for
357a tuple. `[a]` is `a`, `[a b]` the cell `[a b]`, `[a b c]` the
360A tuple, unless it's a trivial 1-tuple, is always marked `%noun`.
362##### `[%ge p=dojo-script]`
364A `%ge` is a generator, a configurable script loaded from the
367The script recipe `++dojo-script` specifies a script path, a list
368of ordered arguments, and a list of keyword arguments. All the
369arguments are recipes. The path specifies a Hoon source file in
372For the path `/fun/make`, the ordered arguments `1`, `2` and `3`,
373and the named arguments `foo` and `bar`, the syntax is:
375 ~fintud-macrep:dojo> +fun/make 1 2 3, =foo (add 2 2), =bar 42
377Unless this non-closed form is the end of a command, it needs to
378be surrounded by `[]` to make it play well with others.
380Generator programming is covered in the dojo developer's guide.
381The user doesn't need to know or notice how the generator gets
382its input (if any), except in one case: a dialog.
384A dialog generator will take over the prompt and ask you
385questions. If this seems terrifying, ^D will abort the dialog,
386the recipe, and the command, and take you back to the dojo.
388##### `[%as p=mark q=dojo-recipe]`
390`%as` is a mark conversion. Since the input to it is another
391recipe, we can chain them to make a conversion pipeline.
393To convert a recipe, just precede it with the converison form, `&mark`:
395 ~fintud-macrep:dojo> &noun (add 2 2)
396 ~fintud-macrep:dojo> &md (add 50 7)
398##### `[%do p=twig q=dojo-recipe]`
400`%do` is a Hoon functino (gate) application. It can also be in a pipeline.
402Its syntax is a hoon expression preceeded by `_`:
404 ~fintud-macrep:dojo> _lore 'hello\0aworld'
405 ~fintud-macrep:dojo> _|=(a=@ (mul 3 a))} (add 2 2)
409A simple HTTP get produces the result as a `%httr` noun.
413Developing dojo generators is the easiest form of Hoon programming.
414Generator scripts are found in the `gen` folder.
418All generator scripts are configured with the same configuration gate:
420 |= $: [now=@da eny=@ bec=beak]
421 [arg=my-arguments opt=my-options]
424We try to minimize boilerplate, but you can't get out of this
425one. The dojo will slam this configuration gate to create your
428The head of the sample is a system context. `now` is the date of
429the call; `eny` is 256 bits of entropy; `bec` is a triple
430`[p=ship q=desk r=case]` (ie, the root of a filesystem path).
431This beak is the path to the script, not the current path within
432the dojo (dojo variables are not, unlike in Unix, visible to
435`arg` and `opt` are whatever you want them to be. (Use `~` if
436you have no arguments or options.) The dojo will replace `arg`
437with the user's ordered arguments, and replace any options in
438`opt` specified by the user's named arguments. (More exactly,
439if the user specifies `=foo 42`, your `opt` is replaced with
442Bear in mind that dojo syntax is list-centric, so your `arg` will
443always end with a `~`. For instance,
445 ~fintud-macrep/dojo> +fun/make 1 2 3
447will generate an `arg` of `[1 2 3 ~]`. Yes, this is the only
448place in Urbit where we do list-centric arguments.
450Note also that script configuration is typed. The user's command
451will fail if there's a type mismatch. But `arg` does not have to
452be a homogeneous list -- just a tuple with `~` on the end. Also,
453you can use `arg=*` and sort out the nouns by hand. Any value
454you don't care about can simply be `*`.
458There are four kinds of generators: builders (with no special
459I/O), dialogs (which read console input), scrapers (which pull
460data from the webs), and synthesizers (which produce another
461generator). Any generator can use `.^` to both read from and
462block (wait for remote or delayed results) on the Urbit global
465A generator produces a cell whose tail is the configuration gate,
466and whose head is `%say` for a builder, `%ask` for a dialog,
467`%get` for a scraper, and `%con` for a constructor.
471A builder just produces a cask (mark-value cell) directly from
472the configuration gate. Here's the simplest builder, with a
481A dialog is a console input form. We recommend using the helpful
482`sole` structures, with
486(If you're interested in building your own dialogs without `sole`
487(not that complicated at all), it's easiest to start by
488reverse-engineering `sole`.)
490Otherwise, a dialog boilerplate (with blank configuration), which
491generates a `my-result` result with mark `%my-result-mark`:
494 ^- (sole-result (cask my-result))
495 %+ sole-so %my-result-mark
498Internally, a `++sole-result` is either a final result or a new
499dialog core with a new prompt. The dojo keeps running the dialog
500until it produces a final result.
502A dialog step can do one of three things: print a message, prompt
503for a value, or finish with a result. These are done with
504`sole-yo`, `sole-lo`, and `sole-so` respectively. Here's a
505simple dialog which uses all of them:
508 ^- (sole-result (cask ,@ud))
509 %+ sole-yo leaf/"let's multiply two numbers..."
510 %+ sole-lo [%& %number "number one: "]
513 %+ sole-lo [%& %number "number two: "]
519`++sole-yo` prints a tank (prettyprint structure). See `++tank`
522`++sole-lo` takes a prompt and a new dialog. In the example,
523`[%& %number "your number: "]` is a `++sole-prompt`. `&` as
524opposed to `|` means input is echoed (not a password).
525`%number` is a history label; all inputs with the same label
526share the same history buffer.
528The `++sole-dialog` is generally built with `++sole-go`, as used
529above. This takes a parsing `++rule` (here `dim:ag`, which
530parses a decimal), and a gate whose sample is the parsed value,
531producing a new dialog.
535Most stuff on the internets is crap, but there's exceptions.
536Sometimes it's nice to get it and compute functions on it.
538A scraper is much like a dialog, except instead of `sole-lo` and
539`sole-go` it uses `sole-at`.
542 %+ sole-yo leaf/"Fetching example.com"
543 %+ sole-at [[& ~ `/com/example] `/ ~]
545 %+ sole-yo leaf/"Fetched."
549`++sole-at` takes a `purl` request url, and a gate through
550which to slam the result `httr`.
554A synthesizer simply produces another recipe. Its
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list