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