on 01ac191 help sign in
367 lines 11 kB history raw
1---
2sort: 4
3next: true
4title: Syntax
5---
7# Hoon syntax
9Hoon's semantics are simple, but unusual. Hoon's syntax is
10complex, and unusual. Sorry.
12## Motivation
14An excuse: the normal human brain doesn't have hardware support
15for math, but it does have hardware support for syntax. Learning
16math is harder than it looks. Learning syntax is easier.
18An explanation: the Hoon syntax is trying to solve three serious
19problems in functional syntax design. These are *terminator
20piles*, *indentation creep*, and *feature/label confusion*.
22## Terminator piles
24*Terminator piles* are like Lisp's stacks of right parenthesess.
25Significant whitespace solves this problem and creates others.
27Hoon has no terminator piles. Except for a 1-space / more-space
28distinction, it has no significant whitespace.
30## Indentation creep
32*Indentation creep* is a problem caused by indentation conventions
33where the indentation point is a function of expression tree
34depth. It's true that short functions are better than long ones,
35but long ones sometimes need to be written.
37A procedural block has a backbone of statements which flows
38straight down. Most expressions are flat and of limited depth.
39With some bulging, a long function flows *down* the page.
41A functional language lacks the expression/statement distinction.
42So a long function means a deep tree. Given normal indentation
43conventions, a long function wants to flow *down and across*.
44This *diagonal* shape fits poorly into most editor windows.
46Thanks to backstep indentation (see below), Hoon programs are
47shaped more or less like procedural programs.
49## Feature/label confusion
51*Feature/label confusion* is any syntax which makes it hard for
52the eye to tell whether a token on the screen is a feature of the
53language, or a label in the program. For example, in Lisp a
54special form has the same syntax as a function call.
56The worst-case result of FLC is "DSL cancer". Every source file
57is effectively written in its own domain-specific language. To
58read a new file is to learn a new language -- "write-only code."
60A fixed reserved-word set, especially with syntax highlighting,
61and especially with orthogonal grammar (in C, you don't write
62`for(a b c)`), may not be too bad. User-level macros, operator
63overloading, even excessive use of higher-order programming,
64can all lead quickly to the tragedy of write-only code.
66Hoon has very weak FLC in keyword style, none in rune style.
67It has no user-level macros or overloading. It does support
68higher-order programming; write-only Hoon can certainly be
69(and has been) written. But good Hoon style is to avoid it.
71# Design
73Because each twig stem has its own bulb, each has its own parser
74rule. We'll describe these grammars as we go through the stems.
76But Hoon has a general syntax design with common principles and
77regularities. We'll cover those here.
79## Glyphs and characters
81Hoon is a heavy punctuation user. To make ASCII great again,
82we've mapped each punctuation glyph to a syllable:
84```
85ace [1 space] gal < pal (
86bar | gap [>1 space, nl] par )
87bas \ gar > sel [
88buc $ hax # sem ;
89cab _ hep - ser ]
90cen % kel { sig ~
91col : ker } soq '
92com , ket ^ tar *
93doq " lus + tec `
94dot . pam & tis =
95fas / pat @ wut ?
96zap !
97```
99You don't need to memorize these glyph names, but it helps. Code
100is often vocalized or subvocalized. "pal" is easier to say,
101aloud or silently, then "left paren."
103Note that the list includes two separate whitespace forms: `ace`
104for a single space, `gap` for 2+, comment or newline. Hoon
105Besides `ace` versus `gap`, whitespace is not significant.
107Comments start with `::` and run to the end of the line. Hard
108tab characters are illegal, and an 80-column right margin is
109strongly encouraged. Really well-groomed Hoon uses a 55-column
110code margin and puts a standard line comment at column 57.
112Hoon does not accept non-ASCII text in source files, except UTF-8
113in quoted strings.
115## Tall and flat forms
117There are two kinds of Hoon expression syntax: *tall* and *flat*.
118Most stems have both tall and flat forms. Tall twigs can contain
119flat twigs, but not vice versa.
121Visually, a tall twig looks like a "statement" and a flat twig
122like an "expression," preserving the attractive visual shape of
123procedural code without the nasty side effects.
125## Regular and irregular forms
127Most stems have *regular forms*, which share a common design.
128There is a regular flat form and a regular tall form; most stems
129implement both. All tall forms are regular.
131Some twigs also have *irregular forms*, which follow no
132principles at all. All irregular forms are flat.
134Some twigs (simple leafy ones) have *only* irregular forms.
136## Keywords versus runes
138A regular form starts with a *sigil*, which is either a
139*keyword* or a *rune* -- at the programmer's choice.
141A *keyword* is `:` and then the stem label - eg, `:cons`.
143A *rune* is a pair of ASCII punctuation marks (a digraph) - eg,
144`:-`. The first glyph in the rune indicates the category - eg,
145`:` runes make cells. Runes can be pronounced by their glyphs or
146by their stem -- for `:-`, you can say either "colhep" or "cons".
148Keywords may be less challenging for early learners. Rune style
149is less cluttered and distracting for experienced programmers;
150the system codebase is all in rune style. Beginners can start
151with keywords and move to runes; start with runes and stick
152with runes; or start with keywords and stick with keywords.
154Here's the FizzBuzz demo code, in idiomatic rune syntax. Compare
155with the [original](../../demo).
157```
158 |= end/atom
159 =/ count 1
160 |- ^- (list tape)
161 ?: =(100 count) ~
162 :_ $(count (add 1 count))
163 ?: =(0 (mod count 15))
164 "FizzBuzz"
165 ?: =(0 (mod count 5))
166 "Fizz"
167 ?: =(0 (mod count 3))
168 "Buzz"
169 (text !>(count))
170```
172## Tall regular form
174Tall regular form starts with the sigil, followed by a `gap`
175(any whitespace except `ace`), followed by a bulb whose twigs are
176separated by `gap`.
178There are four body subtypes: *fixed*, *running*, *jogging*, and
179*battery*. Stems with a *fixed* number of subexpressions
180self-terminate. For instance, `:if` has three subexpressions and
181is self-terminating. Otherwise the twig is terminated by a
182`gap`, then either `==` (*running* or *jogging*, most twigs) or
183`--` (*battery*).
185The *running* body is a list of twigs. The *jogging* body is a
186list of twig pairs, separated by a `gap`. The *battery* body is
187a list of symbol-twig pairs, separated by a gap, prefixed by `++`
188and then a gap.
190This definition is enough to parse. But the proper shape of the
191whitespace gaps demands an informal convention.
193Whitespace design in Hoon is an art, not a science. It involves
194both tall/flat mode switches and well-shaped gaps. (Hoon layout
195could probably be done automatically with reasonable quality.
196But it would at least take machine learning, not a rule engine.)
198There only two real *rules* in Hoon whitespace design: don't
199go past 80 characters, and don't use (completely) blank lines.
200Otherwise, if it looks good and is easy to read, it's good. But
201the best way to learn the art is to do everything by convention
202until you know what you're doing. Here are the conventions:
204### Conventions: *fixed*
206Bulbs with *fixed* fanout use "backstep" indentation, which slopes
207backward and to the right by two spaces per line. The first
208child is two spaces after the end of the sigil.
210Some *1-fixed*, *2-fixed*, *3-fixed* and *4-fixed* examples:
212```
213|.
216=| p
219?: p
220 q
223%^ p
224 q
225 r
227```
229The hope of backstep indentation is that the heaviest twigs are
230at the bottom, keeping code flow vertical rather than diagonal.
231Alternate, reversing
233### Conventions: *running*
235A *running* bulb (a simple child list) puts the first child two
236spaces after the end of the sigil, and the following children
237straight down:
239A *running* example:
241```
242:* p
243 q
244 r
245 s
246 t
247==
248```
250### Conventions: *jogging*
252A *jogging* bulb (a list of child pairs) is like a running bulb,
253but backsteps the head of the pair above the tail. Most jogging
254twigs start with a *fixed* sequence; the first jogging pair is
255below and two steps backward from the last fixed child.
257There are two jogging conventions: *flat* (pair on one line) and
258*tall* (pair split across lines).
260A *flat jogging* example (preceded by *1-fixed* `p`)
262```
263?- p
264 q r
265 s t
266 u v
267==
268```
270A *tall jogging* example (preceded by *1-fixed* `p`):
272```
273?- p
274 q
275 r
276 s
277 t
278 u
279 v
280==
281```
283### Conventions: *battery*
285A *battery* bulb is a list of symbol-twig pairs, for the battery
286of a core. A conventional example:
288```
289|%
290++ foo
291 p
292++ bar
293 q
294--
295```
297## Flat regular form
299Flat regular form starts with the sigil, followed by `pal`
300(`(`, left parenthesis), followed by a bulb whose subexpressions
301are separated by `ace` (one space), followed by `par` (`)`, right
302parenthesis).
304A twig in flat form, `:if`, `?:`, `{$if p/twig q/twig r/twig}`:
306```
307:if(p q r)
309?:(p q r)
310```
312The only exception is *jogging* bodies, in which subexpression
313pairs are separated by commas:
315```
316:make(foo bar 42, baz 55, moo 17)
317```
319There is no flat regular form for *battery* bodies. Be tall.
321## Naming conventions
323Hoon does not enforce any rule on symbols, except that capitals
324are not allowed (use kebab-case). However, a lot of system code
325is written in using "lapidary" conventions that need explanation.
327Naming things is one of the hard problems in CS. Dodging this
328problem is one of the reasons mathematicians use Greek letters,
329not variable names. Meaningful names also interpose a verbal
330interpretation, distracting at best and confusing at worst, on
331the formula or algorithm. Greek letters are not *meaningful*,
332but they are *memorable*. And their interpretation is defined by
333the formula and nothing else.
335### Lapidary and ultralapidary
337In the *lapidary* naming style, labels are pronounceable
338three-letter strings, usually CVC (consonant-vowel-consonant).
339Sometimes they encode a mnemonic, but usually they are just
340memorable. Labels are reused wherever the analogy seems
341appropriate.
343In the *ultralapidary* naming style, labels are single letters,
344starting in order of construction from `a`, or within a tuple
345mold `p`. Hoon uses single-letter names for the same reason
346Algol style languages pass arguments by order, rather than
347keyword. Naming items by order makes sense when there are no
348more than three or four; five is stretching it; six is too many.
350For example, when defining `add`, we want to name the operands
351`a` and `b`. It's silly to call them `foo` and `bar`, let alone
352`left-operand` and `right-operand`. The smaller the scale of an
353algorithm, the simpler its names should be.
355### When in doubt, don't be lapidary
357This works in the other direction: namelessness doesn't scale.
358Most normal code shouldn't use lapidary naming at all. (Everyone
359agrees: there is *way* too much lapidary Hoon in Urbit.)
361Lapidary naming is only for *inherently simple code*: code that
362both aspires to high elegance and clarity, and *is solving a
363simple and elegant problem*.
365Given an ugly or complex problem, lapidary naming is a liability,
366no matter the excellence of the programmer. When in doubt, use
367long names and/or kebab-case.