10Hoon's syntax is unusual, and to beginners it can look a lot more
11complex than it really is. However, we believe that anyone who
12learns Hoon syntax will find that it has a number of advantages.
16Hoon syntax is trying to solve three serious
17problems in functional syntax design. These are *terminator
18piles*, *indentation creep*, and *feature/label confusion*.
22*Terminator piles* are like Lisp's stacks of right parentheses.
23Significant whitespace solves this problem and creates others.
25Hoon has no terminator piles. Except for a 1-space / more-space
26distinction, it has no significant whitespace.
30*Indentation creep* is a problem caused by indentation conventions
31where the indentation point is a function of expression tree
32depth. This problem is especially irritating when working with
33long functions. It's true that short functions are better, but
34long ones sometimes need to be written.
36A procedural block has a backbone of statements which flows
37straight down. Most expressions are flat and of limited depth.
38With some bulging, a long function flows *down* the page.
40A functional language lacks the expression/statement distinction.
41So a long function means a deep tree. Given normal indentation
42conventions, a long function wants to flow *down and across*.
43This *diagonal* shape fits poorly into most editor windows.
45Thanks to backstep indentation (see below), Hoon programs are
46shaped more or less like procedural programs.
48## Feature/label confusion
50*Feature/label confusion* (FLC) is the result of any syntax that
51makes it hard for the eye to tell whether a token on the screen is
52a feature of the language, or a label in the program. For example,
53in Lisp a special form has the same syntax as a function call.
55The worst-case result of FLC is "DSL cancer." Every source file
56is effectively written in its own domain-specific language. To
57read a new file is to learn a new language—"write-only code."
59User-level macros, operator overloading, even excessive use of
60higher-order programming, can all lead quickly to the tragedy of
63Hoon has no FLC, user-level macros, or overloading. It does
64support higher-order programming; write-only Hoon can certainly be
65(and has been) written. But good Hoon style is to avoid it.
69Hoon has a general syntax design with common principles and
70regularities. We'll cover those here.
72## Glyphs and characters
74Hoon source uses ASCII text. Hoon does not accept non-ASCII
75text in source files, except UTF-8 in quoted strings. Hard
76tab characters are illegal.
78Hoon is a heavy punctuation user. Reading off code aloud
79using the proper names of ASCII symbols is tedious, so we've
80mapped each punctuation glyph to a syllable:
83ace [1 space] gal < pal (
84bar | gap [>1 space, nl] par )
97You don't need to memorize these glyph names, but it might help.
98Code is often vocalized or subvocalized. "pal" is easier to say,
99aloud or silently, than "left paren".
101Note that the list includes two separate whitespace forms: `ace`
102for a single space; `gap` is either 2+ spaces or a newline. In Hoon,
103the only significance in whitespace is the difference between
104`ace` and `gap`. Comments also count as `gap` whitespace—they
105start with `::` and run to the end of the line.
107An 80-column right margin is strongly encouraged. Really
108well-groomed Hoon uses a 55-column code margin and puts a standard
109line comment at column 57.
111## Expressions and Runes
113Each regular Hoon expression begins with a
114[rune](https://urbit.org/docs/about/glossary#rune). A rune is a pair
115of ASCII punctuation marks (a digraph)—e.g., `:-`. The first
116glyph in the rune indicates the category—e.g., `:` runes make
117[cells](https://urbit.org/docs/about/glossary#cell) (i.e., ordered
118pairs). We pronounce runes using their glyph names—for `:-`,
121Each rune is followed by one or more subexpressions. The number and
122kind of subexpressions depend on the rune used.
129This twig uses `:-` to produce a cell: `[25 3]`. There are always two
130subexpressions following the `:-` in syntactically correct Hoon code,
131the first of which, when evaluated, becomes the *head* (i.e., the left)
132and the second of which becomes the *tail* (i.e., the right).
134Hoon expressions are sometimes called
135[twigs](https://urbit.org/docs/about/glossary#twig). You'll find that
136Hoon code has a tree-like structure, so you can think of the various
137expressions as twigs of the tree. The subexpressions following the
138rune are sometimes called the *children* of that twig.
140## Tall and flat forms
142There are two kinds of Hoon expression syntax: *tall* and *flat*.
143Most runes can be used in both tall and flat twigs. Tall twigs can
144contain flat twigs, but not vice versa.
146The `:-` expression in the last subsection was in tall form. Here's
151Visually, a tall twig looks like a "statement" and a flat twig
152like an "expression," preserving the attractive visual shape of
153procedural code without the nasty side effects.
155## Regular and irregular forms
157Most runes have *regular forms*, which share a common design.
158There is a regular flat form and a regular tall form; most runes
159have both kinds of implementation. All tall forms are regular.
161Some runes also have *irregular forms*, which follow no
162principles at all. All irregular forms are flat.
169The `.=` rune tests for equality the two subexpressions that
170follow, and returns a boolean. Above is the tall, regular form of
171`.=`. Below is the irregular form:
175Some twigs have *only* irregular forms.
179Tall regular forms start with a rune followed by a `gap`.
180(Remember, a `gap` is any whitespace other than `ace`.) After
181that are the number and types of subexpressions appropriate for
182that rune. Each subexpression is separated from its neighboring
183subexpressions by a `gap`.
185Let's call everything in the twig after the initial rune the twig
186*body*. There are four body subtypes: *fixed*, *running*, *jogging*,
187and *[battery](https://urbit.org/docs/about/glossary#battery)*.
189Runes with a *fixed* number of subexpressions self-terminate. For
190instance, the `:-` and `.=` runes each have two subexpressions
191and are self-terminating. Otherwise the twig is terminated by both
192a `gap`, then either `==` (*running* or *jogging*, most twigs) or
195The *running* body has a list of *children* (i.e., subexpressions).
196The *jogging* body has a list of child pairs, where the members of
197each pair are separated by a `gap`. The *battery* body is
198a list of symbol-child pairs, separated by a gap, prefixed by `++`
201This definition is enough to write Hoon that will parse. But
202writing code with optimal whitespace management requires some
203additional informal conventions.
205Whitespace design in Hoon is an art, not a science. It involves
206both tall/flat mode switches and well-shaped gaps. (Hoon layout
207could probably be done automatically with reasonable quality.
208But it would at least take machine learning, not a rule engine.)
210There are only two real *rules* in Hoon whitespace design: don't
211go past 80 characters, and don't use (completely) blank lines.
212Otherwise, if it looks good and is easy to read, it's good. The
213best way to learn the art is to do everything by convention
214until you know what you're doing. Here are the conventions:
216### Conventions: *fixed*
218Twig bodies with *fixed* fanout use "backstep" indentation, which
219slopes backward and to the right by two spaces per line. The first
220twig child is two spaces after the end of the rune.
222Some *1-fixed*, *2-fixed*, *3-fixed* and *4-fixed* examples:
241In optimal usage of backstep indentation, the most complicated twigs
242are at the bottom, keeping code flow vertical rather than diagonal.
244### Conventions: *running*
246A *running* twig body (a simple child list) puts the first child two
247spaces after the end of the rune, and the following children straight
261### Conventions: *jogging*
263A *jogging* twig body (a list of child pairs) is like a running
264body, but with a pair of children on each line, separated by
265two spaces. Most jogging bodies start with a *fixed* sequence;
266the first jogging pair is below and two steps backward from the
269There are two jogging conventions: *flat* (pair on one line) and
270*tall* (pair split across lines).
272A *flat jogging* example (preceded by *1-fixed* `p`)
282A *tall jogging* example (preceded by *1-fixed* `p`):
295### Conventions: *battery*
297A *battery* body has a list of symbol-child pairs, for the
298[battery](https://urbit.org/docs/about/glossary#battery)
300[core](https://urbit.org/docs/about/glossary#core). A
316Flat regular form starts with the rune, followed by `pal`, `(`
317(left parenthesis), followed by a body whose subexpressions
318are separated by `ace` (one space), followed by `par`, `)` (right
321A twig in flat form, `:if`, `?:`, `{$if p/twig q/twig r/twig}`:
325The only exception is *jogging* bodies, in which subexpression
326pairs are separated by commas:
329foo(bar 42, baz 55, moo 17)
332There is no flat regular form for *battery* bodies. Be tall.
336Hoon does not enforce any rule on symbols, except that capitals
337are not allowed (use kebab-case). However, a lot of system code
338is written using "lapidary" conventions that need explanation.
340Naming things is one of the hard problems in CS. Dodging this
341problem is one of the reasons mathematicians use Greek letters,
342not variable names. Meaningful names also interpose a verbal
343interpretation, distracting at best and confusing at worst, on
344the formula or algorithm. Greek letters are not *meaningful*,
345but they are *memorable*. And their interpretation is defined by
346the formula and nothing else.
348### Lapidary and ultralapidary
350In the *lapidary* naming style, labels are pronounceable
351three-letter strings, usually CVC (consonant-vowel-consonant).
352Sometimes they encode a mnemonic, but usually they are just
353memorable. Labels are reused wherever the analogy seems
356In the *ultralapidary* naming style, labels are single letters,
357starting in order of construction from `a`, or within a tuple
358[mold](https://urbit.org/docs/about/glossary#mold) `p`. Hoon
359uses single-letter names for the same reason Algol style
360languages pass arguments by order, rather than keyword. Naming
361items by order makes sense when there are no more than three or
362four; five is stretching it; six is outright ridiculous.
364For example, when defining `add`, we want to name the operands
365`a` and `b`. It's silly to call them `foo` and `bar`, let alone
366`left-operand` and `right-operand`. The smaller the scale of an
367algorithm, the simpler its names should be.
369### When in doubt, don't be lapidary
371This works in the other direction: namelessness doesn't scale.
372Most normal code shouldn't use lapidary naming at all. (Everyone
373agrees: there is *way* too much lapidary Hoon in Urbit.)
375Lapidary naming is only for *inherently simple code*: code that
376both aspires to high elegance and clarity, and *is solving a
377simple and elegant problem*.
379Given an ugly or complex problem, lapidary naming is a liability,
380no matter the excellence of the programmer. When in doubt, use
381long names and/or kebab-case.
385If you came all this way to learn how to write apps, you're all
386set. This is about all you need to know to start getting your
387hands dirty. Refer back here or to the [standard library](../../hoon/library) when
388needed, but for now, move on to [Arvo](../../arvo) to continue learning.
390If, however, good enough is *not* enough, feel free to dive deeper:
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