5title: Hoon refresher / crash course
11This recapitulates material you've already learned in
12[Hoon](/docs/hoon/). It will be a very abrupt tutorial if you don't know
13Hoon already, but it may be enough in and of itself. If you don't find
14it obvious at first glance, try working up from Hoon.
16Our goal is to get you programming interesting and useful things as soon
17as possible. To get there, we have to quickly cover some of the
18fundamentals of hoon. To do this, we'll walk through two simple
19programs: the first [Project Euler](https://projecteuler.net/) problem
20and [fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
22To run this code, you'll need an urbit, and will have to copy the
23[examples repo](https://github.com/urbit/examples) into it.
25If you haven't installed urbit yet, check out the [installation
26instructions](/docs/using/install). Once urbit is installed, take a look
27at the [basic operation](/docs/using/admin) of your urbit.
29If you haven't copied in the examples repo, running the following
30commands from your urbit directory should do the trick:
32`$ cp -r {wherever-you've-pulled-to}/examples/gall/*/ arvo/`
33`$ cp -r {wherever-you've-pulled-to}/examples/dojo/*/ arvo/`
35Run an example to ensure it worked:
37 ~fintud-macrep:dojo> +examples-euler1
43Let's check out the code for Euler 1. First, the problem:
45 If we list all the natural numbers below 10 that are multiples of
46 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
48 Find the sum of all the multiples of 3 or 5 below 1000.
50Here is the hoon solution (which should be in your pier directory under
51`/gen/examples/euler1`):
54 :: https://projecteuler.net/problem=1
55 :: run in dojo with +examples-euler1
57 :::: /hoon/euler1/examples/gen
72 (add b $(b (add 3 b)))
82 (add b $(b (add b 5)))
86 (add (five a) (three a))
89> Hoon is not generally whitespace sensitive, but we do have two
90> different kinds of whitespace: a single space and a gap, which is two
91> or more spaces or a linebreak. Tabs are taboo. Do not use them.
92> Really. For a more detailed explanation of when to use spaces vs.
93> gaps, see the syntax section before the first exercises.
97Any line that begins with `::` is a comment.
103All you need to know about the lines above is that they call the `++sum`
104function with an argument of `1.000`. We'll cover them in more detail
107### How to form expressions
109Hoon does not typically use reserved words to form expressions. Instead,
110expressions are formed with *runes*: digraphs of two ASCII symbols. Each
111rune takes a specific number of children, either expressions formed by
112other runes or literals that produce their own value (some runes take
113*N* children, and are usually closed with `==`).
115For example, the rune `?:` from line 17 is the classic 'if-then-else'
116statement, and thus takes three children:
118 ?: (lth a b) :: if first child evals to true
119 0 :: then produce result of second
120 (add b $(b (add 3 b))) :: else, produce result of third
122Since runes are such a fundamental structure in Hoon, we found ourselves
123speaking them out loud frequently. It quickly grew cumbersome to have to
124say "question mark, colon" to describe `?:`. To alleviate this problem,
125we came up with our own naming scheme: each ASCII glyph has a
126single-syllable pronunciation phonetically designed to be both easily
127remembered and easily pronounced in conjunction with the other glyphs
128(when forming a rune).
130See the entire naming scheme below.
132 ace [1 space] gal < pel (
133 bar | gap [>1 space, \n] per )
144Using this scheme, we would pronounce `?:` as 'wutcol'.
146For those who prefer to use reserved words to form expressions, you can
147substitute any rune with that rune's keyword, which you can find in
148`++twig` in `/arvo/hoon.hoon`. For example, here's the code for `?:` in
151`{$if p/twig q/twig r/twig} :: ?: if/then/else`
155 ?:(=(1 2) 'this is true' 'this is false')
160 if(=(1 2) 'this is true' 'this is false')
165Now let's quickly walk through this code line-by-line. Lines 12-34 are
166wrapped in a `|%` ('barcen'), which produces a core. Cores are a
167fundamental datatype in Hoon, similar to a struct, class, or object. A
168core is just a map of names to any kind of code, whether it be functions
169or data. Each element in this map begins with a `++` followed by the
170name and the corresponding code. Since `|%` takes an arbitrary number of
171children, it needs to be closed with a `--`.
173> `++` ('luslus') is not technically a rune, since it is only used in
174> core syntax, as shown above.
176Let's step into each of the three arms within our core.
182 (add (five a) (three a))
185`|=` ('bartis') produces a function, much like a lambda in lisp. It
1881. A set of argument(s). In this case our argument set only contains
189 one: `a`, which is required to be an atom or natural number, denoted
1922. The body of the function itself, which is executed when the function
193 is called (in this case, with `(sum 1.000)`). This particular
194 function adds the results of evaluating the gates `++ five` and
195 `++three` with each of their respective input parameters set to `a`.
205 (add b $(b (add 3 b)))
207As above, `++three` takes an integer argument, `a`, and then executes
208the remainder of the code with `a` set to the actual arguments.
210Similarly, `=|` ('tisbar') pushes its first child, `b` into our context
211(in other words, it declares a variable `b`) and executes the remainder
212of the code. However, `b` is not an argument; `=|` sets `b` to the
213default value of whatever type it is declared as. Since the default
214value of an atom is `0`, b is set to `0`.
216> To produce the default value of any given type, use `$*` ('buctar')
217> followed by the type. Alternatively, use the irregular form `*`.
219> > *@ :: produce the default value of atom @
222> > *@p :: produce the phonemic base of atom @
225So now we have two variables: `a` is set to our input, and `b` is
228One way to think about `|-` ('barhep') is that it lays down a recursion
229point. More on this later.
231`^-` ('kethep') is just a cast that sets the result of the remainder of
232the code to an unsigned integer, `@u`.
234In pseudocode, the last three lines read like this: if `a` is less than
235`b`, produce zero. Else, add `b` to the result of rerunning the segment
236of the function following the `|-` with the value of `b` changed to `b`
239The only thing that should look completely unfamiliar to you here is the
240`$(b (add 3 b))`, which causes us to recurse back to our last recursion
241point with the value of `b` set to `(add 3 b)`. Note that we only
242specify what changes (`b` in this case). If you recurse by an actual
243function call, then you have to specify every argument.
245> If you're familiar with Clojure, `|-` is `loop` and `$()` is `recur`.
249Tweak your code to complete the following excercises.
251There are a few runes and some syntax that we have yet to cover that you
252will need to complete the excercises below. For these, please refer to
253our cheatsheat at the bottom.
2551. Read and understand `++five` line by line.
2572. Change `++sum` to accept two variables, `a` and `b`. Pass `a` to
258 `three` and `b` to `five`. Then run the code with `a` set to `1.000`
259 and `q` set to `2.000`.
2613. Check if this new result is under one thousand. If it is, return the
262 string `'result < 1.000'`. If not, return `'result >= 1.000'`.
266 |% ('barcen') start core (collection of named ++ arms; an "object")
267 |= ('bartis') define function
268 =| ('tisbar') define variable from type with default value
269 |- ('barhep') drop a recursion point
271 ?: ('wutcol') if-then-else
273 (function args ...) call function with args
2771. There are two syntaxes for writing Hoon: tallform and wideform.
279In tallform, expressions are formed with either two spaces or a line
280break separating both a rune from its children and each of its children
281from one another. We use tallform when writing multiline expressions.
283For more concise expressions, we use wideform, which is always a single
284line. Wideform can be used inside tallform expressions, but not vice
287Wideform expressions are formed with a rune followed by `()` containing
288its children, all of which are separated by a single space. For example,
289to make a cell of two elements:
293We've already seen wideform in action, for example with
294`=((mod b 3) 0)`. In this case, `=` is actually an irregular form of
295`.=`, which tests its two children for equality.
297Surrounding a function with `()` is an irregular wide form syntax for
298calling a function with *N* arguments. More on this later.
3001. `:-` makes a cell of values. The irregular wide form of this is
301 `[a b]`, with two expressions separated by a single space. While the
302 regular form of this rune takes a fixed number of children (two),
303 its irregular wide form can accept *N* expressions: `[a1..an]`
3052. Cords are one datatype for text in Hoon. They're just a big atom
306 formed from adjacent unicode bytes -- a "c string". To produce a
307 cord, enclose text within single quotes. To set the type of an
308 argument to a cord, use `@t`.
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