on ec69951 help sign in
urbit.org/docs/arvo/basic.md
337 lines 12 kB history raw
1---
2navhome: /docs/
3sort: 11
4next: true
5title: Basic Hoon
6---
8Basic Hoon
9==========
11Our goal is to get you programming interesting and useful things as soon
12as possible. To get there, we have to quickly cover some of the
13fundamentals of [Hoon](/docs/hoon/). To do this, we'll walk through two simple
14programs: the first [Project Euler](https://projecteuler.net/) problem
15and [fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
17To run this code, you'll need an urbit, and will have to either sync or copy the
18[examples repo](https://github.com/urbit/examples) into it.
20## Installation
22First, you'll need a running urbit. Follow our urbit.org [install
23instructions](https://urbit.org/docs/using/install), then
24[setup](https://urbit.org/docs/using/setup) and urbit.
26Follow the *Network install* below if your urbit is running on the live network
27(comets are usually best for development). Follow the *Local install* instead
28if you're on a
29[fake ship](https://urbit.org/fora/posts/~2017.1.5..21.31.04..20f3~/) or are
30otherwise experiencing problems with the network install.
32### Network install
34In your urbit's `:dojo`, run the command:
36 ~your-urbit:dojo> |sync %examples ~ladnub-lorwyn %examples
38Depending on network traffic, this initial merge and sync could take anywhere
39between thirty seconds to several minutes. Upon a successful sync you'll see the
40output:
42 sync succeeded from %examples on ~ladnub-lorwyn to %examples
44In which case, next run the commands:
46 ~your-urbit:dojo> =dir /=examples=
47 ~your-urbit:dojo/examples> |serve %/web
48 ~your-urbit:dojo/examples> |mount %
50If your sync isn't succeeding after a few minutes for whatever reason, run
51`|cancel %examples` in your `:dojo` and follow the local install below instead.
53### Local install
55In your urbit's `:dojo`:
57 ~your-urbit:dojo> |merge %examples our %base, =gem %init
58 ~your-urbit:dojo> =dir /=examples=
59 ~your-urbit:dojo/examples> |serve %/web
60 ~your-urbit:dojo/examples> |mount %
62If `~your-urbit` was installed at `/urbit/path` on your Unix machine, you can
63now find your `%examples` desk at the path `/urbit/path/your-urbit/examples`.
65Lastly, in Unix, clone this repo somewhere and copy in the `examples` files to
66your urbit's new mounted `%examples` desk. You can run the following shell
67commands (*replacing your urbit's examples desk path as necessary*):
69 $ git clone https://github.com/urbit/examples
70 $ for dir in {app,gen,lib,mar,sec,sur,web}; do cp -r ./examples/$dir* /urbit/path/your-urbit/examples; done
72Your `%clay` filesystem should acknowledge the newly added files.
74## Get started!
76Run an example to ensure it worked:
78 ~fintud-macrep:dojo/examples> +project-euler-p1
79 233.168
81Euler 1
82-------
84Let's check out the code for Euler 1. First, the problem:
86 If we list all the natural numbers below 10 that are multiples of
87 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
89 Find the sum of all the multiples of 3 or 5 below 1000.
91Here is the hoon solution (which should be in your pier directory under
92`/examples/gen/project-euler/p1`):
94 :: Project Euler 1
95 :: https://projecteuler.net/problem=1
96 ::
97 :: run in dojo with:
98 :: ~your-urbit:dojo/examples> +project-euler/p1
99 ::
100 :::: /===/gen/project-euler/p1/hoon
101 ::
102 !:
103 ::
104 :- %say |= *
105 :- %noun
106 =< (sum 1.000)
107 ::
108 |%
109 ++ three
110 |= a/@
111 =| b/@
112 |- ^- @u
113 ?: (lth a b)
114 0
115 (add b $(b (add 3 b)))
116 ::
117 ++ five
118 |= a/@
119 =| b/@
120 |- ^- @
121 ?: (lte a b)
122 0
123 ?: =((mod b 3) 0)
124 $(b (add b 5))
125 (add b $(b (add b 5)))
126 ::
127 ++ sum
128 |= a/@u
129 (add (five a) (three a))
130 --
132> Hoon is not generally whitespace sensitive, but we do have two
133> different kinds of whitespace: a single space and a gap, which is two
134> or more spaces or a linebreak. Tabs are taboo. Do not use them.
135> Really. For a more detailed explanation of when to use spaces vs.
136> gaps, see the syntax section before the first exercises.
138### Lines 1-13:
140Any line that begins with `::` is a comment.
142 :- %say |= *
143 :- %noun
144 =< (sum 1.000)
146All you need to know about the lines above is that they call the `++sum`
147function with an argument of `1.000`. We'll cover them in more detail
148later.
150### How to form expressions
152Hoon does not typically use reserved words to form expressions. Instead,
153expressions are formed with *runes*: digraphs of two ASCII symbols. Each
154rune takes a specific number of children, either expressions formed by
155other runes or literals that produce their own value (some runes take
156*N* children, and are usually closed with `==`).
158For example, the rune `?:` from line 20 is the classic 'if-then-else' statement,
159and thus takes three children:
161 ?: (lth a b) :: if first child evals to true
162 0 :: then produce result of second
163 (add b $(b (add 3 b))) :: else, produce result of third
165Since runes are such a fundamental structure in Hoon, we found ourselves
166speaking them out loud frequently. It quickly grew cumbersome to have to
167say "question mark, colon" to describe `?:`. To alleviate this problem,
168we came up with our own naming scheme: each ASCII glyph has a
169single-syllable pronunciation phonetically designed to be both easily
170remembered and easily pronounced in conjunction with the other glyphs
171(when forming a rune).
173See the entire naming scheme below.
175 ace [1 space] gal < pal (
176 bar | gap [>1 space, nl] par )
177 bas \ gar > sel [
178 buc $ hax # sem ;
179 cab _ hep - ser ]
180 cen % kel { sig ~
181 col : ker } soq '
182 com , ket ^ tar *
183 doq " lus + tec `
184 dot . pam & tis =
185 fas / pat @ wut ?
186 zap !
188Using this scheme, we would pronounce `?:` as 'wutcol'.
190### Lines 14-37
192Now let's quickly walk through this code line-by-line. Lines 14-37 are wrapped
193in a `|%` ('[barcen](../../hoon/rune/bar/cen/)'), which produces a
194core. Cores are a fundamental datatype in Hoon, similar to a struct, class, or
195object. A core is just a map of names to any kind of code, whether it be
196functions or data. Each element, called an arm, in this map begins with a `++`
197followed by the name and the corresponding code. Since `|%` takes an arbitrary
198number of children, it needs to be closed with a `--`.
200> `++` ('luslus') is not technically a rune, since it is only used in
201> core syntax, as shown above.
203Let's step into each of the three arms within our core.
205### `++ sum`
207 ++ sum
208 |= a/@u
209 (add (five a) (three a))
210 --
212 `|=` ('[bartis](../../hoon/rune/bar/tis/)') produces a function, much like a lambda in lisp. It
213takes two children:
2151. A set of argument(s). In this case our argument set only contains
216 one: `a`, which is required to be an atom or natural number, denoted
217 by `@`.
2192. The body of the function itself, which is executed when the function is
220 called (in this case, with `(sum 1.000)`). This particular function adds the
221 results of evaluating the gates `++five` and `++three` with each of their
222 respective input parameters set to `a`.
224### ++ three
226 ++ three
227 |= a/@
228 =| b/@
229 |- ^- @u
230 ?: (lth a b)
231 0
232 (add b $(b (add 3 b)))
234As above, `++three` takes an integer argument, `a`, and then executes
235the remainder of the code with `a` set to the actual arguments.
237Similarly, `=|` ('[tisbar](../../hoon/rune/tis-flow/bar-new/)') pushes its first child, `b` into our context
238(in other words, it declares a variable `b`) and executes the remainder
239of the code. However, `b` is not an argument; `=|` sets `b` to the
240default value of whatever type it is declared as. Since the default
241value of an atom is `0`, b is set to `0`.
243> To produce the default value of any given type, use `*` ('tar')
244> followed by the type. This operaction is called *bunt*.
246> > *@ :: produce the default value of atom @
247> 0
248>
249> > *@p :: produce the phonemic base of atom @
250> ~zod
252So now we have two variables: `a` is set to our input, and `b` is
253initialized to `0`.
255One way to think about `|-` ('[barhep](../../hoon/rune/bar/hep/)') is that it lays down a recursion
256point. More on this later.
258`^-` ('[kethep](../../hoon/rune/ket/hep/)') is just a cast that sets the result of the remainder of
259the code to an unsigned integer, `@u`.
261In pseudocode, the last three lines read like this: if `a` is less than
262`b`, produce zero. Else, add `b` to the result of rerunning the segment
263of the function following the `|-` with the value of `b` changed to `b`
264plus three.
266The only thing that should look completely unfamiliar to you here is the
267`$(b (add 3 b))`, which causes us to recurse back to our last recursion
268point with the value of `b` set to `(add 3 b)`. Note that we only
269specify what changes (`b` in this case). If you recurse by an actual
270function call, then you have to specify every argument.
272> If you're familiar with Clojure, `|-` is `loop` and `$()` is `recur`.
274**Exercises**:
276Tweak your code to complete the following exercises.
278There are a few runes and some syntax that we have yet to cover that you
279will need to complete the exercises below. For these, please refer to
280our cheatsheat at the bottom.
2821. Read and understand `++five` line by line.
2842. Change `++sum` to accept two variables, `a` and `b`. Pass `a` to
285 `three` and `b` to `five`. Then run the code with `a` set to `1.000`
286 and `b` set to `2.000`.
2883. Check if this new result is under one thousand. If it is, return the
289 string `'result < 1.000'`. If not, return `'result >= 1.000'`.
291### Review
293 |% ('barcen') start core (collection of named ++ arms; an "object")
294 |= ('bartis') define function
295 =| ('tisbar') define variable from type with default value
296 |- ('barhep') drop a recursion point
297 ^- ('kethep') cast
298 ?: ('wutcol') if-then-else
299 =(a b) test equality
300 (function args ...) call function with args
302Lookup each of these expressions (and all others!) in the [Rune Expressions](../../hoon/rune/) definition.
304### New material
3061. There are two syntaxes for writing Hoon: tallform and wideform.
308 In tallform, expressions are formed with either two spaces or a line
309 break separating both a rune from its children and each of its children
310 from one another. We use tallform when writing multiline expressions.
312 For more concise expressions, we use wideform, which is always a single
313 line. Wideform can be used inside tallform expressions, but not vice
314 versa.
316 Wideform expressions are formed with a rune followed by `()` containing
317 its children, all of which are separated by a single space. For example,
318 to make a cell of two elements, use `:-(a b)`.
320 We've already seen wideform in action, for example with
321 `=((mod b 3) 0)`. In this case, `=` is actually an irregular form of
322 `.=`, which tests its two children for equality.
324 Surrounding a function with `()` is an irregular wide form syntax for
325 calling a function with *N* arguments. More on this later.
3272. For a set of multiple arguments following `|=` ('[bartis](../../hoon/rune/bar/tis/)'), use `{` 'kel' and `}` 'ker.' For example: `{a/@u b/@u}`.
3293. `:-` makes a cell of values. The irregular wide form of this is
330 `[a b]`, with two expressions separated by a single space. While the
331 regular form of this rune takes a fixed number of children (two),
332 its irregular wide form can accept *N* expressions: `[a1..an]`.
3344. Cords are one datatype for text in Hoon. They're just a big atom
335 formed from adjacent unicode bytes -- a "c string". To produce a
336 cord, enclose text within single quotes. To set the type of an
337 argument to a cord, use `@t`.