10Hoon's semantics are simple, but unusual. Hoon's syntax is
11complex, and unusual. Sorry.
15An excuse: the normal human brain doesn't have hardware support
16for math, but it does have hardware support for syntax. Learning
17math is harder than it looks. Learning syntax is easier.
19An explanation: the Hoon syntax is trying to solve three serious
20problems in functional syntax design. These are *terminator
21piles*, *indentation creep*, and *feature/label confusion*.
25*Terminator piles* are like Lisp's stacks of right parentheses.
26Significant whitespace solves this problem and creates others.
28Hoon has no terminator piles. Except for a 1-space / more-space
29distinction, it has no significant whitespace.
33*Indentation creep* is a problem caused by indentation conventions
34where the indentation point is a function of expression tree
35depth. It's true that short functions are better than long ones,
36but long ones sometimes need to be written.
38A procedural block has a backbone of statements which flows
39straight down. Most expressions are flat and of limited depth.
40With some bulging, a long function flows *down* the page.
42A functional language lacks the expression/statement distinction.
43So a long function means a deep tree. Given normal indentation
44conventions, a long function wants to flow *down and across*.
45This *diagonal* shape fits poorly into most editor windows.
47Thanks to backstep indentation (see below), Hoon programs are
48shaped more or less like procedural programs.
50## Feature/label confusion
52*Feature/label confusion* is any syntax which makes it hard for
53the eye to tell whether a token on the screen is a feature of the
54language, or a label in the program. For example, in Lisp a
55special form has the same syntax as a function call.
57The worst-case result of FLC is "DSL cancer." Every source file
58is effectively written in its own domain-specific language. To
59read a new file is to learn a new language -- "write-only code."
61A fixed reserved-word set, especially with syntax highlighting,
62and especially with orthogonal grammar (in C, you don't write
63`for(a b c)`), may not be too bad. User-level macros, operator
64overloading, even excessive use of higher-order programming,
65can all lead quickly to the tragedy of write-only code.
67Hoon has very weak FLC in keyword style, none in rune style.
68It has no user-level macros or overloading. It does support
69higher-order programming; write-only Hoon can certainly be
70(and has been) written. But good Hoon style is to avoid it.
74Because each twig stem has its own bulb, each has its own parser
75rule. We'll describe these grammars as we go through the stems.
77But Hoon has a general syntax design with common principles and
78regularities. We'll cover those here.
80## Glyphs and characters
82Hoon is a heavy punctuation user. To make ASCII great again,
83we've mapped each punctuation glyph to a syllable:
86ace [1 space] gal < pal (
87bar | gap [>1 space, nl] par )
100You don't need to memorize these glyph names, but it helps. Code
101is often vocalized or subvocalized. "pal" is easier to say,
102aloud or silently, then "left paren."
104Note that the list includes two separate whitespace forms: `ace`
105for a single space, `gap` for 2+, comment or newline. Hoon
106Besides `ace` versus `gap`, whitespace is not significant.
108Comments start with `::` and run to the end of the line. Hard
109tab characters are illegal, and an 80-column right margin is
110strongly encouraged. Really well-groomed Hoon uses a 55-column
111code margin and puts a standard line comment at column 57.
113Hoon does not accept non-ASCII text in source files, except UTF-8
116## Tall and flat forms
118There are two kinds of Hoon expression syntax: *tall* and *flat*.
119Most stems have both tall and flat forms. Tall twigs can contain
120flat twigs, but not vice versa.
122Visually, a tall twig looks like a "statement" and a flat twig
123like an "expression," preserving the attractive visual shape of
124procedural code without the nasty side effects.
126## Regular and irregular forms
128Most stems have *regular forms*, which share a common design.
129There is a regular flat form and a regular tall form; most stems
130implement both. All tall forms are regular.
132Some twigs also have *irregular forms*, which follow no
133principles at all. All irregular forms are flat.
135Some twigs (simple leafy ones) have *only* irregular forms.
137## Keywords versus runes
139A regular form starts with a *sigil*, which is either a
140*keyword* or a *rune* -- at the programmer's choice.
142A *keyword* is `:` and then the stem label - e.g., `:cons`.
144A *rune* is a pair of ASCII punctuation marks (a digraph) - e.g.,
145`:-`. The first glyph in the rune indicates the category - e.g.,
146`:` runes make cells. Runes can be pronounced by their glyphs or
147by their stem -- for `:-`, you can say either "colhep" or "cons".
149Keywords may be less challenging for early learners. Rune style
150is less cluttered and distracting for experienced programmers;
151the system codebase is all in rune style. Beginners can start
152with keywords and move to runes; start with runes and stick
153with runes; or start with keywords and stick with keywords.
155Here's the FizzBuzz demo code, in idiomatic rune syntax. Compare
156with the [original](../demo).
163 :_ $(count (add 1 count))
164 ?: =(0 (mod count 15))
166 ?: =(0 (mod count 5))
168 ?: =(0 (mod count 3))
175Tall regular form starts with the sigil, followed by a `gap`
176(any whitespace except `ace`), followed by a bulb whose twigs are
179There are four body subtypes: *fixed*, *running*, *jogging*, and
180*battery*. Stems with a *fixed* number of subexpressions
181self-terminate. For instance, `:if` has three subexpressions and
182is self-terminating. Otherwise the twig is terminated by a
183`gap`, then either `==` (*running* or *jogging*, most twigs) or
186The *running* body is a list of twigs. The *jogging* body is a
187list of twig pairs, separated by a `gap`. The *battery* body is
188a list of symbol-twig pairs, separated by a gap, prefixed by `++`
191This definition is enough to parse. But the proper shape of the
192whitespace gaps demands an informal convention.
194Whitespace design in Hoon is an art, not a science. It involves
195both tall/flat mode switches and well-shaped gaps. (Hoon layout
196could probably be done automatically with reasonable quality.
197But it would at least take machine learning, not a rule engine.)
199There are only two real *rules* in Hoon whitespace design: don't
200go past 80 characters, and don't use (completely) blank lines.
201Otherwise, if it looks good and is easy to read, it's good. But
202the best way to learn the art is to do everything by convention
203until you know what you're doing. Here are the conventions:
205### Conventions: *fixed*
207Bulbs with *fixed* fanout use "backstep" indentation, which slopes
208backward and to the right by two spaces per line. The first
209child is two spaces after the end of the sigil.
211Some *1-fixed*, *2-fixed*, *3-fixed* and *4-fixed* examples:
230The hope of backstep indentation is that the heaviest twigs are
231at the bottom, keeping code flow vertical rather than diagonal.
234### Conventions: *running*
236A *running* bulb (a simple child list) puts the first child two
237spaces after the end of the sigil, and the following children
251### Conventions: *jogging*
253A *jogging* bulb (a list of child pairs) is like a running bulb,
254but backsteps the head of the pair above the tail. Most jogging
255twigs start with a *fixed* sequence; the first jogging pair is
256below and two steps backward from the last fixed child.
258There are two jogging conventions: *flat* (pair on one line) and
259*tall* (pair split across lines).
261A *flat jogging* example (preceded by *1-fixed* `p`)
271A *tall jogging* example (preceded by *1-fixed* `p`):
284### Conventions: *battery*
286A *battery* bulb is a list of symbol-twig pairs, for the battery
287of a core. A conventional example:
300Flat regular form starts with the sigil, followed by `pal`
301(`(`, left parenthesis), followed by a bulb whose subexpressions
302are separated by `ace` (one space), followed by `par` (`)`, right
305A twig in flat form, `:if`, `?:`, `{$if p/twig q/twig r/twig}`:
313The only exception is *jogging* bodies, in which subexpression
314pairs are separated by commas:
317:make(foo bar 42, baz 55, moo 17)
320There is no flat regular form for *battery* bodies. Be tall.
324Hoon does not enforce any rule on symbols, except that capitals
325are not allowed (use kebab-case). However, a lot of system code
326is written in using "lapidary" conventions that need explanation.
328Naming things is one of the hard problems in CS. Dodging this
329problem is one of the reasons mathematicians use Greek letters,
330not variable names. Meaningful names also interpose a verbal
331interpretation, distracting at best and confusing at worst, on
332the formula or algorithm. Greek letters are not *meaningful*,
333but they are *memorable*. And their interpretation is defined by
334the formula and nothing else.
336### Lapidary and ultralapidary
338In the *lapidary* naming style, labels are pronounceable
339three-letter strings, usually CVC (consonant-vowel-consonant).
340Sometimes they encode a mnemonic, but usually they are just
341memorable. Labels are reused wherever the analogy seems
344In the *ultralapidary* naming style, labels are single letters,
345starting in order of construction from `a`, or within a tuple
346mold `p`. Hoon uses single-letter names for the same reason
347Algol style languages pass arguments by order, rather than
348keyword. Naming items by order makes sense when there are no
349more than three or four; five is stretching it; six is outright.
351For example, when defining `add`, we want to name the operands
352`a` and `b`. It's silly to call them `foo` and `bar`, let alone
353`left-operand` and `right-operand`. The smaller the scale of an
354algorithm, the simpler its names should be.
356### When in doubt, don't be lapidary
358This works in the other direction: namelessness doesn't scale.
359Most normal code shouldn't use lapidary naming at all. (Everyone
360agrees: there is *way* too much lapidary Hoon in Urbit.)
362Lapidary naming is only for *inherently simple code*: code that
363both aspires to high elegance and clarity, and *is solving a
364simple and elegant problem*.
366Given an ugly or complex problem, lapidary naming is a liability,
367no matter the excellence of the programmer. When in doubt, use
368long names and/or kebab-case.
372If you came all this way to learn how to write apps, you're all
373set. This is about all you need to know to start getting your
374hands dirty. Refer back here or to the [standard library](../../hoon/library) when
375needed, but for now, move on to [Arvo](../../arvo) to continue learning.
377If, 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