on 4ff1e79 help sign in
urbit.org/docs/arvo/basic.md
310 lines 11 kB history raw
1---
2navhome: /docs
3sort: 1
4next: true
5title: Hoon refresher / crash course
6---
8Basic Hoon
9==========
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
38 233.168
40Euler 1
41-------
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`):
53 :: project euler 1
54 :: https://projecteuler.net/problem=1
55 :: run in dojo with +examples-euler1
56 ::
57 :::: /hoon/euler1/examples/gen
58 ::
59 :- %say |= *
60 :- %noun
61 =< (sum 1.000)
62 ::
63 :::: ~sivtyv-barnel
64 ::
65 |%
66 ++ three
67 |= a/@
68 =| b/@
69 |- ^- @u
70 ?: (lth a b)
71 0
72 (add b $(b (add 3 b)))
74 ++ five
75 |= a/@
76 =| b/@
77 |- ^- @
78 ?: (lte a b)
79 0
80 ?: =((mod b 3) 0)
81 $(b (add b 5))
82 (add b $(b (add b 5)))
84 ++ sum
85 |= a/@u
86 (add (five a) (three a))
87 --
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.
95### Lines 1-11:
97Any line that begins with `::` is a comment.
99 :- %say |= *
100 :- %noun
101 =< (sum 1.000)
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
105later.
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 )
134 bas \ gar > sel [
135 buc $ hax # sem ;
136 cab _ hep - ser ]
137 cen % kel { soq '
138 col : ker } tar *
139 com , ket ^ tec `
140 doq " lus + tis =
141 dot . pam & wut ?
142 fas / pat @ zap !
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
149`++twig`:
151`{$if p/twig q/twig r/twig} :: ?: if/then/else`
153Instead of:
155 ?:(=(1 2) 'this is true' 'this is false')
156 'this is false'`
158You can write:
160 if(=(1 2) 'this is true' 'this is false')
161 'this is false'
163### Lines 12-34
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.
178### `++ sum`
180 ++ sum
181 |= a/@
182 (add (five a) (three a))
183 --
185`|=` ('bartis') produces a function, much like a lambda in lisp. It
186takes two children:
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
190 by `@`.
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`.
197### ++ three
199 ++ three
200 |= a/@
201 =| b/@
202 |- ^- @u
203 ?: (lth a b)
204 0
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 @
220> 0
221>
222> > *@p :: produce the phonemic base of atom @
223> ~zod
225So now we have two variables: `a` is set to our input, and `b` is
226initialized to `0`.
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`
237plus three.
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`.
247**Exercises**:
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'`.
264### Review
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
270 ^- ('kethep') cast
271 ?: ('wutcol') if-then-else
272 =(a b) test equality
273 (function args ...) call function with args
275### New material
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
285versa.
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:
291 :-(a b)
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`.