on 021ce99 help sign in
urbit.org/docs/hoon/syntax.md
379 lines 12 kB history raw
1---
2navhome: /docs
3sort: 4
4next: true
5title: Syntax
6---
8# Hoon syntax
10Hoon's semantics are simple, but unusual. Hoon's syntax is
11complex, and unusual. Sorry.
13# Motivation
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*.
23## Terminator piles
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.
31## Indentation creep
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.
72# Design
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:
85```
86ace [1 space] gal < pal (
87bar | gap [>1 space, nl] par )
88bas \ gar > sel [
89buc $ hax # sem ;
90cab _ hep - ser ]
91cen % kel { sig ~
92col : ker } soq '
93com , ket ^ tar *
94doq " lus + tec `
95dot . pam & tis =
96fas / pat @ wut ?
97zap !
98```
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. In Hoon,
106the only significance in whitespace is the difference between
107`ace` and `gap`.
109Comments start with `::` and run to the end of the line. Hard
110tab characters are illegal, and an 80-column right margin is
111strongly encouraged. Really well-groomed Hoon uses a 55-column
112code margin and puts a standard line comment at column 57.
114Hoon does not accept non-ASCII text in source files, except UTF-8
115in quoted strings.
117## Tall and flat forms
119There are two kinds of Hoon expression syntax: *tall* and *flat*.
120Most stems have both tall and flat forms. Tall twigs can contain
121flat twigs, but not vice versa.
123Visually, a tall twig looks like a "statement" and a flat twig
124like an "expression," preserving the attractive visual shape of
125procedural code without the nasty side effects.
127## Regular and irregular forms
129Most stems have *regular forms*, which share a common design.
130There is a regular flat form and a regular tall form; most stems
131implement both. All tall forms are regular.
133Some twigs also have *irregular forms*, which follow no
134principles at all. All irregular forms are flat.
136Some twigs (simple leafy ones) have *only* irregular forms.
138## Keywords versus runes
140A regular form starts with a *sigil*, which is either a
141*keyword* or a *rune* -- at the programmer's choice.
143A *keyword* is `:` and then the stem label - e.g., `:cons`.
145A *rune* is a pair of ASCII punctuation marks (a digraph) - e.g.,
146`:-`. The first glyph in the rune indicates the category - e.g.,
147`:` runes make cells. Runes can be pronounced by their glyphs or
148by their stem -- for `:-`, you can say either "colhep" or "cons".
150Keywords may be less challenging for early learners. Rune style
151is less cluttered and distracting for experienced programmers;
152the system codebase is all in rune style. Beginners can start
153with keywords and move to runes; start with runes and stick
154with runes; or start with keywords and stick with keywords.
156Here's the FizzBuzz demo code, in idiomatic rune syntax. Compare
157with the [original](../demo).
159```
160 |= end/atom
161 =/ count 1
162 |- ^- (list tape)
163 ?: =(end count) ~
164 :_ $(count (add 1 count))
165 ?: =(0 (mod count 15))
166 "FizzBuzz"
167 ?: =(0 (mod count 5))
168 "Fizz"
169 ?: =(0 (mod count 3))
170 "Buzz"
171 (pave !>(count))
172```
174## Tall regular form
176Tall regular form starts with the sigil, followed by a `gap`
177(any whitespace except `ace`), followed by a bulb whose twigs are
178separated by `gap`.
180There are four body subtypes: *fixed*, *running*, *jogging*, and
181*battery*. Stems with a *fixed* number of subexpressions
182self-terminate. For instance, `:if` has three subexpressions and
183is self-terminating. Otherwise the twig is terminated by a
184`gap`, then either `==` (*running* or *jogging*, most twigs) or
185`--` (*battery*).
187The *running* body is a list of twigs. The *jogging* body is a
188list of twig pairs, separated by a `gap`. The *battery* body is
189a list of symbol-twig pairs, separated by a gap, prefixed by `++`
190and then a gap.
192This definition is enough to parse. But the proper shape of the
193whitespace gaps demands an informal convention.
195Whitespace design in Hoon is an art, not a science. It involves
196both tall/flat mode switches and well-shaped gaps. (Hoon layout
197could probably be done automatically with reasonable quality.
198But it would at least take machine learning, not a rule engine.)
200There are only two real *rules* in Hoon whitespace design: don't
201go past 80 characters, and don't use (completely) blank lines.
202Otherwise, if it looks good and is easy to read, it's good. But
203the best way to learn the art is to do everything by convention
204until you know what you're doing. Here are the conventions:
206### Conventions: *fixed*
208Bulbs with *fixed* fanout use "backstep" indentation, which slopes
209backward and to the right by two spaces per line. The first
210child is two spaces after the end of the sigil.
212Some *1-fixed*, *2-fixed*, *3-fixed* and *4-fixed* examples:
214```
215|.
218=| p
221?: p
222 q
225%^ p
226 q
227 r
229```
231The hope of backstep indentation is that the heaviest twigs are
232at the bottom, keeping code flow vertical rather than diagonal.
235### Conventions: *running*
237A *running* bulb (a simple child list) puts the first child two
238spaces after the end of the sigil, and the following children
239straight down:
241A *running* example:
243```
244:* p
245 q
246 r
247 s
248 t
249==
250```
252### Conventions: *jogging*
254A *jogging* bulb (a list of child pairs) is like a running bulb,
255but backsteps the head of the pair above the tail. Most jogging
256twigs start with a *fixed* sequence; the first jogging pair is
257below and two steps backward from the last fixed child.
259There are two jogging conventions: *flat* (pair on one line) and
260*tall* (pair split across lines).
262A *flat jogging* example (preceded by *1-fixed* `p`)
264```
265?- p
266 q r
267 s t
268 u v
269==
270```
272A *tall jogging* example (preceded by *1-fixed* `p`):
274```
275?- p
276 q
277 r
278 s
279 t
280 u
281 v
282==
283```
285### Conventions: *battery*
287A *battery* bulb is a list of symbol-twig pairs, for the battery
288of a core. A conventional example:
290```
291|%
292++ foo
293 p
294++ bar
295 q
296--
297```
299## Flat regular form
301Flat regular form starts with the sigil, followed by `pal`
302(`(`, left parenthesis), followed by a bulb whose subexpressions
303are separated by `ace` (one space), followed by `par` (`)`, right
304parenthesis).
306A twig in flat form, `:if`, `?:`, `{$if p/twig q/twig r/twig}`:
308```
309:if(p q r)
311?:(p q r)
312```
314The only exception is *jogging* bodies, in which subexpression
315pairs are separated by commas:
317```
318:make(foo bar 42, baz 55, moo 17)
319```
321There is no flat regular form for *battery* bodies. Be tall.
323## Naming conventions
325Hoon does not enforce any rule on symbols, except that capitals
326are not allowed (use kebab-case). However, a lot of system code
327is written in using "lapidary" conventions that need explanation.
329Naming things is one of the hard problems in CS. Dodging this
330problem is one of the reasons mathematicians use Greek letters,
331not variable names. Meaningful names also interpose a verbal
332interpretation, distracting at best and confusing at worst, on
333the formula or algorithm. Greek letters are not *meaningful*,
334but they are *memorable*. And their interpretation is defined by
335the formula and nothing else.
337### Lapidary and ultralapidary
339In the *lapidary* naming style, labels are pronounceable
340three-letter strings, usually CVC (consonant-vowel-consonant).
341Sometimes they encode a mnemonic, but usually they are just
342memorable. Labels are reused wherever the analogy seems
343appropriate.
345In the *ultralapidary* naming style, labels are single letters,
346starting in order of construction from `a`, or within a tuple
347mold `p`. Hoon uses single-letter names for the same reason
348Algol style languages pass arguments by order, rather than
349keyword. Naming items by order makes sense when there are no
350more than three or four; five is stretching it; six is outright
351ridiculous.
353For example, when defining `add`, we want to name the operands
354`a` and `b`. It's silly to call them `foo` and `bar`, let alone
355`left-operand` and `right-operand`. The smaller the scale of an
356algorithm, the simpler its names should be.
358### When in doubt, don't be lapidary
360This works in the other direction: namelessness doesn't scale.
361Most normal code shouldn't use lapidary naming at all. (Everyone
362agrees: there is *way* too much lapidary Hoon in Urbit.)
364Lapidary naming is only for *inherently simple code*: code that
365both aspires to high elegance and clarity, and *is solving a
366simple and elegant problem*.
368Given an ugly or complex problem, lapidary naming is a liability,
369no matter the excellence of the programmer. When in doubt, use
370long names and/or kebab-case.
372## Freedom
374If you came all this way to learn how to write apps, you're all
375set. This is about all you need to know to start getting your
376hands dirty. Refer back here or to the [standard library](../../hoon/library) when
377needed, but for now, move on to [Arvo](../../arvo) to continue learning.
379If, however, good enough is *not* enough, feel free to dive deeper: