on 140ac0e help sign in
412 lines 13 kB history raw
1---
2logo: black
3sort: 1
4next: true
5title: Hoon refresher / crash course
6---
8# Basic Hoon
10(This recapitulates material you've already learned in Core Hoon.
11It will be a very abrupt tutorial if you don't know Hoon already,
12but it may just suffice. If you don't find it obvious at first
13glance, read it over again
15Our goal is to get you programming interesting and useful things
16as soon as possible. To get there we have to quickly cover some
17of the fundamentals of hoon. To do this we'll walk through two
18simple programs: the first [Project
19Euler](https://projecteuler.net/) problem and
20[fizzbuzz](https://en.wikipedia.org/wiki/Fizz_buzz).
22To run this code, you'll need an urbit, and you'll need the
23`%examples` desk from `~zod`. If you haven't installed
24urbit yet, check out the [installation
25instructions](http://urbit.org/docs/user/install). Once urbit is
26intalled, take a look at the [basic
27operation](http://urbit.org/docs/user/basic) of your urbit.
29If you haven't pulled the examples desk from `~zod`, do
30so now:
32 ~fintud-macrep:dojo> |merge %examples ~zod %examples
33 >=
34 [time passes...]
35 merged with strategy %init
37The merge could take several minutes; you'll know it's done when
38"merged with strategy %init" is printed. Mount the new files to
39your Unix pier directory:
41 ~fintud-macrep:dojo> |mount /=examples=
43Switch desks to run commands from the `%examples` desk:
45 ~fintud-macrep:dojo> =dir /=examples=
46 =% /~fintud-macrep/examples/~2015.11.13..02.25.00..41e9/
48Run an example:
50 ~fintud-macrep:dojo> +euler1
51 233.168
53## Euler 1
55Let's check out the code for Euler 1. First, the problem:
57```
58If we list all the natural numbers below 10 that are multiples of
593 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
61Find the sum of all the multiples of 3 or 5 below 1000.
62```
64Here is the hoon solution (which should be in your pier directory
65under `/examples/gen/euler1.hoon`):
67```
68:: project euler 1
69:: https://projecteuler.net/problem=1
70:: run in dojo with +euler1
71::
72:::: /hoon/euler1/gen
73 ::
74:- %say |= *
75:- %noun
76=< (sum 1.000)
77::
78:::: ~fintud-macrep
79 ::
80|%
81++ three
82 |= a=@
83 =| b=@
84 |- ^- @u
85 ?: (lth a b)
86 0
87 (add b $(b (add 3 b)))
89++ five
90 |= a=@
91 =| b=@
92 |- ^- @
93 ?: (lte a b)
94 0
95 ?: =((mod b 3) 0)
96 $(b (add b 5))
97 (add b $(b (add b 5)))
99++ sum
100 |= a=@u
101 (add (five a) (three a))
102--
103```
105> Hoon is not generally whitespace sensitive, but we do have two
106> different kinds of whitespace: a single space and a gap, which
107> is two or more spaces or a linebreak. Tabs are taboo. Do not
108> use them. Really. For a more detailed explanation of when to
109> use spaces vs. gaps, see the syntax section before the first
110> excercises.
112### Lines 1-11:
114Any line that begins with `::` is a comment.
116 :- %say |= *
117 :- %noun
118 =< (sum 1.000)
120All you need to know about the lines above is that they call the
121`++sum` function with an argument of `1.000`. We'll cover them in
122more detail later.
124### How to form expressions
126Hoon does not use reserved words to form expressions. Instead,
127expressions are formed with runes, which are diagraphs of two
128ascii symbols. Each rune takes a specific number of
129children--either expressions formed by other runes or literals
130that produce their own value.
132For example, the rune `?:` from line 17 is the classic
133'if-then-else' statement, and thus takes three children:
135 ?: (lth a b) :: if first child evals to true
136 0 :: then produce result of second
137 (add b $(b (add 3 b))) :: else, produce result of third
139Since runes are such a fundamental structure in Hoon, we found
140ourselves speaking them out loud frequently. It quickly grew
141cumbersome to have to say "question mark, colon" to describe
142`?:`. To alleviate this problem, we came up with our own naming
143scheme: each ascii glyph has a single syllable pronunciation
144phonetically designed to be both easily remembered and easily
145pronounced in conjunction with the other glyphs (when forming a
146rune).
148See the entire naming schema below/or link to it:
150```
151 ace [1 space] gal < pel (
152 bar | gap [>1 space, nl] per )
153 bas \ gar > sel [
154 buc $ hax # sem ;
155 cab _ hep - ser ]
156 cen % kel { soq '
157 col : ker } tar *
158 com , ket ^ tec `
159 doq " lus + tis =
160 dot . pam & wut ?
161 fas / pat @ zap !
162```
164Using our naming scheme `?:` is said 'wut col'.
166### Lines 12-34
168Now let's quickly walk through this code line-by-line. Lines
16912-34 are wrapped in a `|%` (pronounced 'bar cen'), which
170produces a core, a fundamental datatype in hoon similar to a
171struct, class, or object. A core is just a map of names
172to any kind of code, whether it be functions or data. Each
173element in this map begins with a `++` followed by the name and
174the corresponding code. Since `|%` takes an arbitrary number of
175children, it needs to be closed with a `--`.
177> `++` is not technically a rune, since it is only used in core
178> syntax as shown above
180Let's step into each of the three arms within our core.
182### `++ sum`
184 ++ sum
185 |= a=@
186 (add (five a) (three a))
187 --
189`|=` produces a function, much like a lambda in lisp. It takes two children:
191- A set of argument(s). In this case our argument set only
192 contains one: `a` which is required to be an atom or natural
193 number, denoted by `@`.
195- The body of the function itself, which is executed when the
196 function is called (in this case, with `(sum 1.000)`). This
197 particular function adds the results of evaluating the gates `++
198 five` and `++three` with each of their respective input
199 parameters set to `a`.
201### ++ three
203 ++ three
204 |= a=@
205 =| b=@
206 |- ^- @u
207 ?: (lth a b)
208 0
209 (add b $(b (add 3 b)))
211As above, `++three` takes an integer argument, `a`, and then
212executes the remainder of the code with `a` set to the actual
213arguments.
215Similarly, `=|` pushes its first child, `b` into our context (in
216other words, it declares a variable `b`) and executes the
217remainder of the code. However, `b` is not an argument; `=|`
218sets `b` to the default value of whatever type it is declared as.
219Since the default value of an atom is `0`, b is set to `0`.
221So now we have two variables: `a` is set to our input, and `b` is
222initialized to `0`.
224The easiest way to think about `|-` that it lays down a recursion
225point. More on this later.
227`^-` is just a cast that sets the result of the remainder of the
228code to an unsigned integer, `@u`.
230In pseudocode, the last three lines read like this: if `a` is
231less than `b`, produce zero. Else, add `b` to the result of
232rerunning the segment of the function following the `|-` with the
233value of `b` changed to `b` plus three.
235The only thing that should look completely unfamiliar to you here
236is the `$(b (add 3 b))`, which causes us to recurse back to our
237last recursion point with the value of `b` set to `(add 3 b)`.
238Note that we only specify what changes (`b` in this case). If
239you recurse by an actual function call, then you have to specify
240every argument.
242> If you're familiar with Clojure, `|-` is `loop` and `$()` is
243> recur.
245**Exercises**:
247Please tweak your code to complete the following excercises.
249There are a few runes and some syntax that we have yet to cover that
250you will need to complete the excercises below. For these, please
251refer to our cheatsheat at the bottom.
253- Read and understand `++five` line by line.
255- Change `++sum` to accept two variables, `a` and `b`. Pass `a`
256 to three and `b` to five. Then run the code with `a` set to
257 `1.000` and b set to `2.000`.
259- Check if this new result is under one thousand. If it is,
260 return the string 'result is less than one thousand'. If not,
261 return 'result is greater than or equal to one thousand'.
263```
264Review
266|% start core (collection of named ++ arms)
267|= define function
268=| define variable from type with default value
269|- drop a recursion point
270^- cast
271?: if-then-else
272=(a b) test equality
273(function args ...) call function
275New material
277- :- make a cell of values. The irregular wide form of this is
278 [a b] with two expressions separated by a single space.
280- Cords are one datatype for text in hoon. They're just a big
281 atom formed from adjacent unicode bytes -- a "c string". To
282 produce a cord enclose text within single quotes. To set the type
283 of an argument to a cord, use @t.
285- There are two syntaxes for writing Hoon: tall form and wide
286 form.
288 In tall form, expressions are formed with either two spaces or
289 a line break separating both a rune from its children and each
290 of its children from one another. We use tall form when writing
291 multiline expressions.
293 For more concise expressions, we use wideform, which is always
294 a single line. Wideform can be used inside tall form
295 expressions, but not vice versa.
297 Wideform expressions are formed with a rune followed by ()
298 containing its children, all of which are separated by a
299 single space. For example to make a cell of two elements:
301 :-(a b)
303 We've already seen wideform in action, for example with
304 =((mod b 3) 0). In this case = is actually an irregular form
305 of .=, which tests its two children for equality.
307 Another irregular form is [a b] for :-(a b)
309 Surrounding a function with () is an irregular wide form
310 syntax for calling a function with n arguments.
311```
314## The subject
316Now we're going to cover the boiler plate that we skimmed over
317earlier.
319 :- %say |= *
320 :- %noun
321 =< (sum [1.000 2.000])
323This program is a cell of two elements: the first, `%say`, tells
324the interpreter what to produce--in this case a value.
326The second element is `|=`, which we know produces a function.
327`|=`'s first child is its argument(s), which in this case is any
328noun (`*`). Its second child is the remainder of the program.
330Similarly, the rest of the program is a cell of the literal
331`%noun`, which tells the shell that we're producing a value of
332type `noun`, and the second child contains the code that we run
333to actually produce our value of the type `noun`.
335`=<` is a rune that takes two children. The second child is the
336context against which we run the first child. So in this case, we
337are running the expression `(sum 1.000)` against everything
338contained within the `|%`. In Hoon, we call the code executed the
339"formula" and its context the "subject".
341```
342::::::::::::::::::::::::::::::
343=< (sum 1.000) :: formula
344::::::::::::::::::::::::::::::
345|% ::
346++ three ::
347 |= a=@ ::
348 =| b=@ ::
349 |- ^- @u ::
350 ?: (lth a b) ::
351 0 ::
352 (add b $(b (add 3 b))) ::
353 ::
354++ five ::
355 |= a=@ :: subject
356 =| b=@ ::
357 |- ^- @ ::
358 ?: (lte a b) ::
359 0 ::
360 ?: =((mod b 3) 0) ::
361 $(b (add b 5)) ::
362 (add b $(b (add b 5))) ::
363 ::
364++ sum ::
365 |= a=@u ::
366 (add (five a) (three a)) ::
367-- ::
368::::::::::::::::::::::::::::::
369```
371In nearly every language there is a similar concept of a
372"context" in which expressions are executed. For example, in C
373this includes things like the call stack, stack variables, and so
374on.
376Hoon is unique in that this context is a first-class value.
377Scheme allows a sort of reification of the context through
378continutations, and some may see a parallel to Forth's stack, but
379Hoon takes takes the concept one step further.
381Our starting subject is the standard library, which is defined in
382`/arvo/hoon.hoon` and `/arvo/zuse.hoon`. This is where functions
383like `add` are defined. When we define a core with `|%`, we
384don't throw away the subject (i.e. the standard library); rather,
385we stack the new core on top of the old subject so that both are
386accessible.
388**Exercises**:
390- Pass `++sum` its arguments (`2000` and `3000`) from the
391 commandline.
393- Comment out all of the arms of the `|%`. Now add another arm
394 and call it `++add`, have it accept two arguments and procduce
395 42 (regardless of input). Change the `=<` line to `[(add 5 7)
396 (^add 5 7)]`. Can you recognize what's happening?
398Cheatsheet:
400- To pass arguments from the command line to a program, you
401 replace the `*` in the first line of the boiler plate to
402 `[^ [[arg=TYPE ~] ~]]` where `TYPE` is replaced with the
403 type of argument you're expecting. Then `+euler1 a` from
404 the dojo sets `arg` to `a`.
405- The empty list is `~`
406- Lisp-style cons (construct a cell/prepend an element) is
407 `[new-element list]`
408- For example, the first three positive integers are `[1 2 3
409 ~]`
410- `gte` tests whether `a` is greater than or equal to `b`.
411- `mod` runs the modulo operation on two atoms.
412- See the [basic math section]() for more info.