on 4e5c9fe help sign in
urbit.org/docs/arvo/basic.md
322 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:
32Make sure you've mounted your `%home` desk:
34```
35~fintud-macrep:dojo> |mount %
36```
38Then, copy the example into it
40```
41$ cp -r {urbit-examples}/gall/*/ {your-pier}/home/
42$ cp -r {urbit-examples}/dojo/*/ {your-pier}/home/
43```
45Run an example to ensure it worked:
47 ~fintud-macrep:dojo> +examples-euler1
48 233.168
50Euler 1
51-------
53Let's check out the code for Euler 1. First, the problem:
55 If we list all the natural numbers below 10 that are multiples of
56 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
58 Find the sum of all the multiples of 3 or 5 below 1000.
60Here is the hoon solution (which should be in your pier directory under
61`/gen/examples/euler1`):
63 :: project euler 1
64 :: https://projecteuler.net/problem=1
65 :: run in dojo with +examples-euler1
66 ::
67 :::: /hoon/euler1/examples/gen
68 ::
69 :- %say |= *
70 :- %noun
71 =< (sum 1.000)
72 ::
73 :::: ~sivtyv-barnel
74 ::
75 |%
76 ++ three
77 |= a/@
78 =| b/@
79 |- ^- @u
80 ?: (lth a b)
81 0
82 (add b $(b (add 3 b)))
84 ++ five
85 |= a/@
86 =| b/@
87 |- ^- @
88 ?: (lte a b)
89 0
90 ?: =((mod b 3) 0)
91 $(b (add b 5))
92 (add b $(b (add b 5)))
94 ++ sum
95 |= a/@u
96 (add (five a) (three a))
97 --
99> Hoon is not generally whitespace sensitive, but we do have two
100> different kinds of whitespace: a single space and a gap, which is two
101> or more spaces or a linebreak. Tabs are taboo. Do not use them.
102> Really. For a more detailed explanation of when to use spaces vs.
103> gaps, see the syntax section before the first exercises.
105### Lines 1-11:
107Any line that begins with `::` is a comment.
109 :- %say |= *
110 :- %noun
111 =< (sum 1.000)
113All you need to know about the lines above is that they call the `++sum`
114function with an argument of `1.000`. We'll cover them in more detail
115later.
117### How to form expressions
119Hoon does not typically use reserved words to form expressions. Instead,
120expressions are formed with *runes*: digraphs of two ASCII symbols. Each
121rune takes a specific number of children, either expressions formed by
122other runes or literals that produce their own value (some runes take
123*N* children, and are usually closed with `==`).
125For example, the rune `?:` from line 17 is the classic 'if-then-else'
126statement, and thus takes three children:
128 ?: (lth a b) :: if first child evals to true
129 0 :: then produce result of second
130 (add b $(b (add 3 b))) :: else, produce result of third
132Since runes are such a fundamental structure in Hoon, we found ourselves
133speaking them out loud frequently. It quickly grew cumbersome to have to
134say "question mark, colon" to describe `?:`. To alleviate this problem,
135we came up with our own naming scheme: each ASCII glyph has a
136single-syllable pronunciation phonetically designed to be both easily
137remembered and easily pronounced in conjunction with the other glyphs
138(when forming a rune).
140See the entire naming scheme below.
142 ace [1 space] gal < pel (
143 bar | gap [>1 space, \n] per )
144 bas \ gar > sel [
145 buc $ hax # sem ;
146 cab _ hep - ser ]
147 cen % kel { soq '
148 col : ker } tar *
149 com , ket ^ tec `
150 doq " lus + tis =
151 dot . pam & wut ?
152 fas / pat @ zap !
154Using this scheme, we would pronounce `?:` as 'wutcol'.
156For those who prefer to use reserved words to form expressions, you can
157substitute any rune with that rune's keyword, which you can find in
158`++twig` in `/arvo/hoon.hoon`. For example, here's the code for `?:` in
159`++twig`:
161`{$if p/twig q/twig r/twig} :: ?: if/then/else`
163Instead of:
165 ?:(=(1 2) 'this is true' 'this is false')
166 'this is false'`
168You can write:
170 :if(=(1 2) 'this is true' 'this is false')
171 'this is false'
173### Lines 12-34
175Now let's quickly walk through this code line-by-line. Lines 12-34 are
176wrapped in a `|%` ('[barcen](../../hoon/twig/bar-core/cen-core/)'), which produces a core. Cores are a
177fundamental datatype in Hoon, similar to a struct, class, or object. A
178core is just a map of names to any kind of code, whether it be functions
179or data. Each element in this map begins with a `++` followed by the
180name and the corresponding code. Since `|%` takes an arbitrary number of
181children, it needs to be closed with a `--`.
183> `++` ('luslus') is not technically a rune, since it is only used in
184> core syntax, as shown above.
186Let's step into each of the three arms within our core.
188### `++ sum`
190 ++ sum
191 |= a/@
192 (add (five a) (three a))
193 --
195`|=` ('[bartis](../../hoon/twig/bar-core/tis-gate/)') produces a function, much like a lambda in lisp. It
196takes two children:
1981. A set of argument(s). In this case our argument set only contains
199 one: `a`, which is required to be an atom or natural number, denoted
200 by `@`.
2022. The body of the function itself, which is executed when the function
203 is called (in this case, with `(sum 1.000)`). This particular
204 function adds the results of evaluating the gates `++ five` and
205 `++three` with each of their respective input parameters set to `a`.
207### ++ three
209 ++ three
210 |= a/@
211 =| b/@
212 |- ^- @u
213 ?: (lth a b)
214 0
215 (add b $(b (add 3 b)))
217As above, `++three` takes an integer argument, `a`, and then executes
218the remainder of the code with `a` set to the actual arguments.
220Similarly, `=|` ('[tisbar](../../hoon/twig/tis-flow/bar-new/)') pushes its first child, `b` into our context
221(in other words, it declares a variable `b`) and executes the remainder
222of the code. However, `b` is not an argument; `=|` sets `b` to the
223default value of whatever type it is declared as. Since the default
224value of an atom is `0`, b is set to `0`.
226> To produce the default value of any given type, use `*` ('tar')
227> followed by the type. This operaction is called *bunt*.
229> > *@ :: produce the default value of atom @
230> 0
231>
232> > *@p :: produce the phonemic base of atom @
233> ~zod
235So now we have two variables: `a` is set to our input, and `b` is
236initialized to `0`.
238One way to think about `|-` ('[barhep](../../hoon/twig/bar-core/hep-loop/)') is that it lays down a recursion
239point. More on this later.
241`^-` ('[kethep](../../hoon/core/ket-cast/hep-cast/)') is just a cast that sets the result of the remainder of
242the code to an unsigned integer, `@u`.
244In pseudocode, the last three lines read like this: if `a` is less than
245`b`, produce zero. Else, add `b` to the result of rerunning the segment
246of the function following the `|-` with the value of `b` changed to `b`
247plus three.
249The only thing that should look completely unfamiliar to you here is the
250`$(b (add 3 b))`, which causes us to recurse back to our last recursion
251point with the value of `b` set to `(add 3 b)`. Note that we only
252specify what changes (`b` in this case). If you recurse by an actual
253function call, then you have to specify every argument.
255> If you're familiar with Clojure, `|-` is `loop` and `$()` is `recur`.
257**Exercises**:
259Tweak your code to complete the following exercises.
261There are a few runes and some syntax that we have yet to cover that you
262will need to complete the exercises below. For these, please refer to
263our cheatsheat at the bottom.
2651. Read and understand `++five` line by line.
2672. Change `++sum` to accept two variables, `a` and `b`. Pass `a` to
268 `three` and `b` to `five`. Then run the code with `a` set to `1.000`
269 and `q` set to `2.000`.
2713. Check if this new result is under one thousand. If it is, return the
272 string `'result < 1.000'`. If not, return `'result >= 1.000'`.
274### Review
276 |% ('barcen') start core (collection of named ++ arms; an "object")
277 |= ('bartis') define function
278 =| ('tisbar') define variable from type with default value
279 |- ('barhep') drop a recursion point
280 ^- ('kethep') cast
281 ?: ('wutcol') if-then-else
282 =(a b) test equality
283 (function args ...) call function with args
285Lookup each of these expressions (and all others!) in the [Twig Expressions](../../hoon/twig/) definition.
287### New material
2891. There are two syntaxes for writing Hoon: tallform and wideform.
291In tallform, expressions are formed with either two spaces or a line
292break separating both a rune from its children and each of its children
293from one another. We use tallform when writing multiline expressions.
295For more concise expressions, we use wideform, which is always a single
296line. Wideform can be used inside tallform expressions, but not vice
297versa.
299Wideform expressions are formed with a rune followed by `()` containing
300its children, all of which are separated by a single space. For example,
301to make a cell of two elements:
303 :-(a b)
305We've already seen wideform in action, for example with
306`=((mod b 3) 0)`. In this case, `=` is actually an irregular form of
307`.=`, which tests its two children for equality.
309Surrounding a function with `()` is an irregular wide form syntax for
310calling a function with *N* arguments. More on this later.
3121. `:-` makes a cell of values. The irregular wide form of this is
313 `[a b]`, with two expressions separated by a single space. While the
314 regular form of this rune takes a fixed number of children (two),
315 its irregular wide form can accept *N* expressions: `[a1..an]`
3172. Cords are one datatype for text in Hoon. They're just a big atom
318 formed from adjacent unicode bytes -- a "c string". To produce a
319 cord, enclose text within single quotes. To set the type of an
320 argument to a cord, use `@t`.