on 93773de help sign in
476 lines 17 kB history raw
1---
2next: false
3sort: 2
4spam: true
5title: Hoon 101.2: syntax
6---
7# Hoon 101.2: full-contact syntax
9In [chapter 0](0-nouns), we read about nouns. In [chapter 1](1-twigs),
10we discovered twigs and legs.
12Up till now, we've done everything in the dojo, Hoon's shell /
13REPL. Now it's time to actually write a real Hoon source file,
14and get a bit deeper into the syntax.
16## How to use this tutorial
18Ideally, you've installed an Urbit planet (if you have a ticket)
19or comet (if you don't). See the [user doc](../../../user).
21We recommend opening up the dojo and just typing the examples;
22you don't know a language until you know it in your fingers.
23Also, make sure you've worked through the chapters in order.
25## Building a simple generator
27In Urbit there's a variety of source file roles, distinguished by
28the magic paths they're loaded from: `/gen` for generators,
29`/ape` for appliances, `/lib` for libraries, etc.
31We'll start with a generator, the simplest kind of Urbit program.
33### Create a sandbox desk
35A desk is the Urbit equivalent of a `git` branch. We're just
36playing around here and don't intend to soil our `%home` desk with
37test files. So let's make a sandbox:
38```
39|sync %sandbox our %home
40```
42You just merged the `%home` desk on your own ship into a new
43`%sandbox` desk. `%sandbox` has everything in `%home`, but we'll
44add more. Future changes in `%home` (such as our over-the-air
45updates) will also propagate into `%sandbox`.
47> Desks are always born in merges; it makes no sense to create an
48empty desk, because anything you do in a desk depends on other
49files in the desk. For instance, your file types (marks) are
50defined by source files in the same desk.
52### Mount the sandbox from Unix
54Run the command
55```
56~tasfyn-partyv:dojo> |mount /=sandbox=/gen %gen
57```
58This mounts the `/gen` folder from the `%sandbox` desk in your Unix
59directory `~/tasfyn-partyv/gen`.
61The mount is a two-way sync, "Dropbox style." When you edit a
62Unix file and save, your edit is automatically committed as a
63change in the `%sandbox` desk. If you change `%sandbox` files
64from Urbit, these changes will also propagate to Unix.
66### Execute from the sandbox
68Let's set the dojo desk to `%sandbox`:
69```
70~tasfyn-partyv:dojo> =dir /=sandbox=
71=% /~tasfyn-partyv/sandbox/~2015.11.13..02.49.37..9e6c/
72```
73Your prompt will change to:
74```
75~tasfyn-partyv:dojo/sandbox
76```
78### Write hello, world
80Let's build the simplest possible kind of generator, a builder.
82First, configure your favorite Unix text editor to work with
83Hoon. There are Hoon modes for vim, emacs and Sublime in the
84`extras/` directory of the github repo.
86Second, create the file `~/tasfyn-partyv/gen/test.hoon`.
87Paste this text into it:
88```
89:- %say |= * :- %noun
90[%hello %world]
91```
92Get the spaces exactly right, please. Hoon is not in general a
93whitespace-sensitive language, but the difference between one space and
94two-or-more matters. And for the moment, think of
95```
96:- %say |= * :- %noun
97```
98as gibberish boilerplate, like `#include "stdio.h"` at the start of a C
99program.
101Now, run your builder:
102```
103~tasfyn-partyv:dojo/sandbox> +test
104[%hello %world]
105```
106This is your first Hoon *program* per se. Congrats!
108## Hoon syntax 101
110But what's up with this syntax?
112### Some syntactic relatives
114The relationship between ASCII and human programming languages
115is like the relationship between the electric guitar and
116rock-and-roll. If it doesn't have a guitar, it's not rock.
117If it doesn't use ASCII, it's not a programming language.
119Some great rock guitarists play three chords, like Johnny Ramone;
120some shred it up, like Jimmy Page. If Lisp is the Ramones of
121syntax, Perl or APL is Led Zeppelin. No one has any right to rag
122on Perl or APL, but Hoon is a "metalhead" language that shreds
123its ASCII very differently.
125### The case for heavy metal
127The philosophical case for a metalhead language is threefold.
128One, human beings are much better at associating meaning with
129symbols than they think they are. Two, a programming language is
130a professional tool and not a plastic beach shovel.
132> "There's a guitar player, a harp player, a double-bass player,
133all holding up their blisters. Imagine if you downloaded a
134library off the internet... and it gave you blisters! Right? The
135horror! And yet... every musician has overcome a barrier to entry
136similar to this." — Rich Hickey
138And three, the alternative to heavy metal is keywords. When you
139use a keyword language, not only are you forcing the programmer
140to tiptoe around a ridiculous maze of reserved words. You're
141expressing your program through two translation steps:
142symbol->English and English->computation.
144When you shred, you are going direct: symbol->computation. A
145pure-functional language with syntax on the metalhead principle
146creates a sense of "seeing the function" which no keyword
147language can quite duplicate. Also, all the words you see on the
148screen are actually meaningful terms in the program.
150But a great metalhead language should *not* be user-extensible.
151That way lies King Crimson. (Maybe Haskell is King Crimson: the
152prog-rock of programming languages.) A language is a standard;
153if users can do whatever with ASCII, there is no standard. If a
154metal language can work, it's only by rigorous consistency and
155predictability. No macros, operator overloading, etc, etc.
157### A glyphic bestiary
159Any metalhead language you don't yet know is line noise. Let's
160get you up to speed as fast as possible.
162A programming language needs to be not just read but said. But
163no one wants to say "ampersand." Therefore, we've taken the
164liberty of assigning three-letter names to all ASCII glyphs.
166Some of these bindings are obvious and some aren't. You'll be
167genuinely surprised at how easy they are to remember:
168```
169 ace [1 space] gal < pel (
170 bar | gap [>1 space, nl] per )
171 bas \ gar > sel [
172 buc $ hax # sem ;
173 cab _ hep - ser ]
174 cen % kel { soq '
175 col : ker } tar *
176 com , ket ^ tec `
177 doq " lus + tis =
178 dot . pam & wut ?
179 fas / pat @ zap !
180 sig ~
181```
182It's fun to confuse the muggles by using these outside Urbit.
184Hoon is not whitespace-sensitive, except that its grammar defines
185two distinct whitespace tokens: `ace`, a single space, and `gap`,
186anything else. `\t`, `\r`, and `\l` choke the parser and should
187not appear in your file.
189A few digraphs also have irregular sounds:
190```
191== stet
192-- shed
193++ slus
194-> lark
195-< lush
196+> dark
197+< dush
198```
200You might remember wondering where the "lark syntax" of chapter 1
201got its name. Lark syntax is read in digraphs from the left, so
202`+>+` is `darklus`.
204> `+>+` is of course `cdddr` in Lisp.
206### The shape of a twig
208As we learned in chapter 1, a twig - the parsed form of a Hoon
209expression - is a noun. As usual in Hoon, the easiest way to
210explain both the syntax that compiles into that noun, and the
211semantic meaning of the noun, is the noun's physical structure.
213#### Autocons
215A twig is always a cell, and any cell of twigs is a twig
216producing a cell. As an homage to Lisp, we call this
217"autocons."
219Where you'd write `(cons a b)` in Lisp, you write `[a b]` in
220Hoon. The Lisp expression, in Hoon syntax, would be `[%cons a b
221~]`. But the Hoon twig is just `[a b]`.
223The `???` prefix prints a twig as a noun instead of running it.
224Let's see autocons in action:
225```
226~tasfyn-partyv:dojo/sandbox> ??? 42
227[%dtzy p=%ud q=42]
228~tasfyn-partyv:dojo/sandbox> ??? 0x2a
229[%dtzy p=%ux q=42]
230~tasfyn-partyv:dojo/sandbox> ??? [42 0xa]
231[[%dtzy p=%ud q=42] [%dtzy p=%ux q=42]]
232```
234#### The stem-bulb pattern
236If the head of your twig is a cell, it's an autocons. If the
237head is an atom, it's an unpronounceable four-letter symbol like
238the `%dtzy` above.
240Except for the funny autocons case, twigs have the same shape
241we see in the `span` mold, which we met in chapter 0. It's
242essentially a variant record, the most common data structure
243ever. In Hoon it's called a *kelp*.
245The head of a kelp (like `%dtzy` above) is called the *stem*.
246The tail (like `[%ux 42]`) is the *bulb*.
248> Think about how to encode tagged data in a noun. It seems
249obvious that the noun is a cell, where the head of the cell is
250the tag (stem) and the tail is the data (bulb). Then, all these
251nouns are cells whose head is an atom. This leaves two noun
252shapes "out of band": atoms, and cells whose head is a cell.
254> Since no twig is an atom, a cell `[twig twig]` is always a cell
255whose head is a cell. So we can distinguish "autocons" from all
256stem-bulb nouns, and assign it specific semantics.
258#### Runes and stems
260A *rune* is a digraph - a sequence of two ASCII glyphs. If you
261know C, you know digraphs like `!=` and `?:` and are used to
262reading them as single characters.
264In Hoon you can *say* runes as words: "zaptis" and "wutcol"
265respectively. If we had to say "exclamation point equals" and
266"question-colon" all the time, we'd just die.
268Most twig stems are made from runes, by concatenating the glyph
269names and removing the vowels. For example, the rune `=+`,
270pronounced "tislus," becomes the stem `%tsls`. (Note that in
271most noun implementations, this is a 31-bit direct value.)
273> Some twig stems (like `%dtzy`) are not runes, simply because
274they don't have regular-form syntax and don't need to use
275precious ASCII real estate. They are otherwise no different.
277An important point to note about runes: they're organized. The
278first glyph in the rune defines a category. For instance, runes
279starting with `.` compute intrinsics; runes starting with `|`
280produce cores; etc.
282Another important point about runes: they come in two flavors,
283"natural" (stems interpreted directly by the compiler) and
284"synthetic" (macros, essentially).
286> Language food fight warning: one advantage of Hoon over Lisp
287is no gensyms. All Hoon macros are perfectly hygienic. Another
288advantage is that Hoon has no (user-level) macros. In Hoon
289terms, nobody gets to invent their own runes, because that way
290lies DSL write-only chaos. But if we had user-level macros,
291they'd be perfectly hygienic as well.
293#### Tall and wide regular forms
295A good rune example is the simple rune `=+`, pronounced "tislus",
296which becomes the stem `%tsls`. A `%tsls` twig has the mold
297`[%tsls p=twig q=twig]`.
299The very elegance of functional languages creates a visual
300problem that imperative languages lack. An imperative language
301has distinct statements (with side effects) and (usually pure)
302expressions; it's natural that in most well-formatted code,
303statements flow vertically down the screen, and expressions grow
304horizontally across this. This interplay creates a natural and
305relaxing shape on your screen.
307In a functional language, there's no difference. The trivial
308functional syntax is Lisp's, which has two major problems. One:
309piles of expression terminators build up at the bottom of complex
310functions. Two: the natural shape of code is diagonal. The more
311complex a function, the more it wants to besiege the right
312margin. The children of a node have to start to the right of its
313parent, so the right margin bounds the tree depth.
315Hoon does not completely solve these problems, but alleviates
316them. In Hoon, there are actually two regular syntax forms for
317most twig cases: "tall" and "wide" form. Tall twigs can contain
318wide twigs, but not vice versa, so the visual shape of a program
319is very like that of a statements-and-expressions language.
321Also, in tall mode, most runes don't need terminators. Take
322`=+`, for example. Since the parser knows to expect exactly
323two twigs after the `=+` rune, it doesn't need any extra syntax
324to tell it that it's done.
326Let's try a wide `=+` in the dojo:
327```
328~tasfyn-partyv:dojo/sandbox> =+(planet=%world [%hello planet])
329[%hello %world]
330```
331(`=+` seems to be some sort of variable declaration? Let's not
332worry about it right now. We're on syntax.)
334The wide syntax for a `=+` twig, or any binary rune: `(`, the
335first subtwig, one space, the second subtwig, and `)`). To read
336this twig out loud, you'd say:
337```
338tislus pel planet tis cen world ace sel cen hello ace planet ser per
339```
340> Various colloquialisms inevitably creep into this usage. "tis" not
341in a rune gets contracted to "is"; "ace" is often just assumed; etc.
343Let's try a tall `=+` in `test.hoon`:
344```
345:- %say |= * :- %noun
346=+ planet=%world
347[%hello planet]
348```
349The tall syntax for a `=+` twig, or any binary rune: the rune, at
350least two spaces or one newline, the first subtwig, at least two
351spaces or one newline, the second subtwig. Again, tall subtwigs
352can be tall or wide; wide subtwigs have to be wide.
354(Note that our boilerplate line is a bunch of tall runes on one
355line, with two-space gaps. This is unusual but quite legal, and
356not to be confused with the actual wide form.)
358To read this twig out loud, you'd say:
359```
360tislus gap planet is cen world gap nep cen hello ace planet pen
361```
362#### Layout conventions
364Should you use wide twigs or tall twigs? When? How? What
365should your code look like? You're the artist. Except for the
366difference between one space (`ace`) and more space (`gap`), the
367parser doesn't care how you format your code. Hoon is not Go --
368there are no fixed rules for doing it right.
370> Keep lines under 80 characters, though. The parser doesn't
371enforce this yet. But it will, so watch out!
373#### Backstep indentation
375Note that the "variable declaration" metaphor of `=+` works
376perfectly here. Because `[%hello planet]` -- despite being a
377subtree of the the `=+` twig -- is at the same indent level. A
378variable declaration shouldn't add indent depth. And `=+`
379doesn't. Our code flows down the screen, not down and to the
380right, and of course there are no superfluous terminators.
382Another example, using a ternary rune with a strange resemblance
383to C:
384```
385:- %say |= * :- %noun
386=+ planet=%world
387?: =(%world planet)
388 [%hello planet]
389[%goodbye planet]
390```
391This is called "backstep" indentation. Not all the children of
392`?:` ("wutcol", `%wtcl`) are at the same indent as the parent;
393but one of them is.
395It's not always the case when backstepping that the largest
396subtwig is at the bottom and loses no indent, but it often is.
397And we do a lot to help you maintain this.
399For instance, `=+` ("tislus") is a binary rune: `=+(a b)`. In
400most cases of `=+` the heavy twig is `b`, but sometimes it's `a`.
401So we can use its friend the `=-` rune ("tishep") to get the same
402semantics with the right shape: `=-(b a)`. Similarly, instead of
403`?:(a b c)`, we can write `?.(a c b)`.
405Not all runes have tuple structure; some are n-ary, and use
406the `==` terminator (again, pronounced "stet"):
407```
408:- %say |= * :- %noun
409=+ planet=%world
410?+ planet
411 [%unknown planet]
412 %world [%hello planet]
413 %ocean [%goodbye planet]
414==
415```
416So we occasionally lose right-margin as we descend a deep twig.
417But we can keep this lossage low with good layout design.
419#### Irregular forms
421There are more regular forms than we've shown above, but not a
422lot more. Hoon would be quite easy to learn if it was only its
423regular forms. It wouldn't be as easy to read or use, though.
424The learning curve is important, but not all-important.
426Some stems (like the `%dtzy` constants above) obviously don't and
427can't have any kind of regular form (which is why `%dtzy` is not
428a real digraph rune). Many of the true runes have only regular
429forms. But some have irregular forms. Irregular forms are
430always wide, but there is no other constraint on their syntax.
432We've already encountered one of the irregular forms: `foo=42`
433from the last chapter, and `planet=%world` here. Let's unpack
434this twig:
435```
436~tasfyn-partyv:dojo/sandbox> ?? %world
437 [%cube 431.316.168.567 %atom %tas]
438%world
440~tasfyn-partyv:dojo/sandbox> ??? %world
441[%dtzz %tas 431.316.168.567]
442```
443Clearly, `%dtzz` is one of our non-regulars. But we can wrap it
444with our irregular form:
445```
446~tasfyn-partyv:dojo/sandbox> ?? planet=%world
447 [%face %planet [%cube 431.316.168.567 %atom %tas]]
448planet=%world
450~tasfyn-partyv:dojo/sandbox> ??? planet=%world
451[%ktts %planet %dtzz %tas 431.316.168.567]
452```
453Since `%ktts` is "kettis", ie, `^=`, this has to be the irregular
454form of
455```
456~tasfyn-partyv:dojo/sandbox> ^=(planet %world)
457planet=world
458```
459So if we wrote our example without this irregular form, it'd be
460```
461:- %say |= * :- %noun
462=+ ^=(planet %world)
463[%hello planet]
464```
465Or with a gratuitous use of tall form:
466```
467:- %say |= * :- %noun
468=+ ^= planet %world
469[%hello planet]
470```
471## Progress
473Now you know how to read Hoon! For fun, try to pronounce more of
474the code on this page. Please don't laugh too hard at yourself.
476In the [next chapter](3-program), we'll actually write a real program...