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](../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](../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 Hoon 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 just called
135[hoons](../about/glossary/#-a-hoon), because a rune's subexpression can itself
136be a Hoon expression (i.e. another rune). You'll start to see this tree-like,
137recursive structure the more you program in Hoon. You can think of one Hoon
138file being composed of multiple hoons. The subexpressions following the
139rune are sometimes called the *children* of that hoon.
141## Tall and flat forms
143There are two kinds of Hoon expression syntax: *tall* and *flat*.
144Most runes can be used in both tall and flat hoons. Tall hoons can
145contain flat hoons, but not vice versa.
147The `:-` expression in the last subsection was in tall form. Here's
152Visually, a tall hoon looks like a "statement" and a flat hoon
153like an "expression," preserving the attractive visual shape of
154procedural code without the nasty side effects.
156## Regular and irregular forms
158Most runes have *regular forms*, which share a common design.
159There is a regular flat form and a regular tall form; most runes
160have both kinds of implementation. All tall forms are regular.
162Some runes also have *irregular forms*, which follow no
163principles at all. All irregular forms are flat.
170The `.=` rune tests for equality the two subexpressions that
171follow, and returns a boolean. Above is the tall, regular form of
172`.=`. Below is the irregular form:
176Some hoons have *only* irregular forms.
180Tall regular forms start with a rune followed by a `gap`.
181(Remember, a `gap` is any whitespace other than `ace`.) After
182that are the number and types of subexpressions appropriate for
183that rune. Each subexpression is separated from its neighboring
184subexpressions by a `gap`.
186Let's call everything in the hoon after the initial rune the hoon
187*body*. There are four body subtypes: *fixed*, *running*, *jogging*,
188and *[battery](../about/glossary/#-battery)*.
190Runes with a *fixed* number of subexpressions self-terminate. For
191instance, the `:-` and `.=` runes each have two subexpressions
192and are self-terminating. Otherwise the hoon is terminated by both
193a `gap`, then either `==` (*running* or *jogging*, most hoons) or
196The *running* body has a list of *children* (i.e., subexpressions).
197The *jogging* body has a list of child pairs, where the members of
198each pair are separated by a `gap`. The *battery* body is
199a list of symbol-child pairs, separated by a gap, prefixed by `++`
202This definition is enough to write Hoon that will parse. But
203writing code with optimal whitespace management requires some
204additional informal conventions.
206Whitespace design in Hoon is an art, not a science. It involves
207both tall/flat mode switches and well-shaped gaps. (Hoon layout
208could probably be done automatically with reasonable quality.
209But it would at least take machine learning, not a rule engine.)
211There are only two real *rules* in Hoon whitespace design: don't
212go past 80 characters, and don't use (completely) blank lines.
213Otherwise, if it looks good and is easy to read, it's good. The
214best way to learn the art is to do everything by convention
215until you know what you're doing. Here are the conventions:
217### Conventions: *fixed*
219Rune bodies with *fixed* fanout use "backstep" indentation, which
220slopes backward and to the right by two spaces per line. The first
221hoon child is two spaces after the end of the rune.
223Some *1-fixed*, *2-fixed*, *3-fixed* and *4-fixed* examples:
242In optimal usage of backstep indentation, the most complicated hoons
243are at the bottom, keeping code flow vertical rather than diagonal.
245### Conventions: *running*
247A *running* hoon body (a simple child list) puts the first child two
248spaces after the end of the rune, and the following children straight
262### Conventions: *jogging*
264A *jogging* hoon body (a list of child pairs) is like a running
265body, but with a pair of children on each line, separated by
266two spaces. Most jogging bodies start with a *fixed* sequence;
267the first jogging pair is below and two steps backward from the
270There are two jogging conventions: *flat* (pair on one line) and
271*tall* (pair split across lines).
273A *flat jogging* example (preceded by *1-fixed* `p`)
283A *tall jogging* example (preceded by *1-fixed* `p`):
296### Conventions: *battery*
298A *battery* body has a list of symbol-child pairs, for the
299[battery](../about/glossary/#-battery)
301[core](../about/glossary/#-core). A
317Flat regular form starts with the rune, followed by `pal`, `(`
318(left parenthesis), followed by a body whose subexpressions
319are separated by `ace` (one space), followed by `par`, `)` (right
322A hoon in flat form, `?:` ("wutcol"), `[%if p=hoon q=hoon r=hoon]`:
326The only exception is *jogging* bodies, in which subexpression
327pairs are separated by commas:
330foo(bar 42, baz 55, moo 17)
333There is no flat regular form for *battery* bodies. Be tall.
337Hoon does not enforce any rule on symbols, except that capitals
338are not allowed (use kebab-case). However, a lot of system code
339is written using "lapidary" conventions that need explanation.
341Naming things is one of the hard problems in CS. Dodging this
342problem is one of the reasons mathematicians use Greek letters,
343not variable names. Meaningful names also interpose a verbal
344interpretation, distracting at best and confusing at worst, on
345the formula or algorithm. Greek letters are not *meaningful*,
346but they are *memorable*. And their interpretation is defined by
347the formula and nothing else.
349### Lapidary and ultralapidary
351In the *lapidary* naming style, labels are pronounceable
352three-letter strings, usually CVC (consonant-vowel-consonant).
353Sometimes they encode a mnemonic, but usually they are just
354memorable. Labels are reused wherever the analogy seems
357In the *ultralapidary* naming style, labels are single letters,
358starting in order of construction from `a`, or within a tuple
359[mold](../about/glossary/#-mold) `p`. Hoon
360uses single-letter names for the same reason Algol style
361languages pass arguments by order, rather than keyword. Naming
362items by order makes sense when there are no more than three or
363four; five is stretching it; six is outright ridiculous.
365For example, when defining `add`, we want to name the operands
366`a` and `b`. It's silly to call them `foo` and `bar`, let alone
367`left-operand` and `right-operand`. The smaller the scale of an
368algorithm, the simpler its names should be.
370### When in doubt, don't be lapidary
372This works in the other direction: namelessness doesn't scale.
373Most normal code shouldn't use lapidary naming at all. (Everyone
374agrees: there is *way* too much lapidary Hoon in Urbit.)
376Lapidary naming is only for *inherently simple code*: code that
377both aspires to high elegance and clarity, and *is solving a
378simple and elegant problem*.
380Given an ugly or complex problem, lapidary naming is a liability,
381no matter the excellence of the programmer. When in doubt, use
382long names and/or kebab-case.
386If you came all this way to learn how to write apps, you're all
387set. This is about all you need to know to start getting your
388hands dirty. Refer back here or to the [standard library](../library/) when
389needed, but for now, move on to [Arvo](../../arvo/) to continue learning.
391If, 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