urbit/pub/docs/dev/hoon/principles/3-program.md

351 lines
9.9 KiB
Markdown
Raw Normal View History

---
next: false
sort: 3
2015-11-21 04:36:01 +03:00
spam: true
title: Hoon 101.3: an algorithm
---
# Hoon 101.3: an algorithm
In [chapter 0](0-nouns), we read about nouns. In [chapter 1](1-twigs),
we discovered twigs and legs. In [chapter 2](2-syntax), we learned
Hoon syntax and created our first source file.
Now it's time for an actual, meaningful *algorithm*.
## How to use this tutorial
Ideally, you've installed an Urbit planet (if you have a ticket)
or comet (if you don't). See the [user doc](../../../user).
We recommend opening up the dojo and just typing the examples;
you don't know a language until you know it in your fingers.
Also, make sure you've worked through the chapters in order.
## Goal: a decrement generator
Our algorithm is the classic Urbit example: decrement.
If you learned [Nock](../../nock) before Hoon, you've already
written decrement. If not, all you need to know is that the only
built-in arithmetic operator in Nock is increment. To decrement,
we need to count up to the result with a simple loop.
## A practical subject
As we've seen, Hoon works by running a twig against a subject.
In chapter 1, we made a simple test subject that was just a few
constants, and applied some simple twigs to it.
This time, we'll actually put useful working data in the subject,
building up more and more complex subjects as we go.
## Subject: nil
We'll start with the empty subject `~`:
```
:- %say |= * :- %noun
=> ~
[%hello %world]
```
The `=>` rune ("tisgar", `%tsgr`)), for `=>(p q)` executes `p`
against the subject, then uses that product as the subject of
`q`.
> We've already used an irregular form of `=>`, or to be more
precise its mirror `=<` ("tisgal", `%tsgl`). In chapter 1, when we wrote
`+3:test`, we meant `=>(test +3)` or `=<(+3 test)`.
What is `~`? It's Hoon `nil`, a zero atom:
```
~tasfyn-partyv:dojo/sandbox> ?? ~
[%cube 0 [%atom %n]]
~
```
We use `~` for list terminators and the like. Obviously, since
`[%hello %world]` is just a constant, a nil subject works as
well as any:
```
~tasfyn-partyv:dojo/sandbox> +test
[%hello %world]
```
## Subject: `arg=@`
Above, we used an empty subject to avoid the very complex,
interesting subject your generator twig gets by default.
But a decrement generator needs to get an argument from the
command line -- the number we're trying to decrement.
This involves changing the `test.hoon` boilerplate a little.
Again, don't worry about the boilerplate line just yet:
```
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
=> arg=arg
[%hello arg]
~tasfyn-partyv:dojo/sandbox> +test 42
[%hello 42]
```
> `=> arg=arg` looks a little odd. We wouldn't ordinarily do
this; we're just trying to keep the subject simple.
In case there's any doubt about the subject (remember from
chapter 1 that `.` means `+1`, the whole subject):
```
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
=> arg=arg
.
~tasfyn-partyv:dojo/sandbox> +test 42
arg=42
```
## An increment generator
We can even write a trivial increment generator using `.+`,
or even better its irregular form `+`:
```
:- %say |= [* [[arg=@ud ~] ~]] :- %noun
=> arg=arg
+(arg)
~tasfyn-partyv:dojo/sandbox> +test 42
43
```
We'll assume these same first two lines for the rest of the
examples in this chapter.
## Cores: one more kind of span
To decrement, we need a loop. To write a loop, we need yet
another kind of noun: the *core*. Briefly, a core is a `[code
data]` pair. Our new `span` mold:
```
++ span
$% [%atom p=@tas]
[%cell p=span p=span]
[%core p=span q=(map ,@tas twig)]
[%cube p=* q=span]
[%face p=@tas q=span]
==
```
### Structure of a core
The core is a cell `[battery payload]`. The payload is data, the
battery is code -- a tree of Nock formulas.
In the `%core` span, the payload is described by an arbitrary
span. The battery is described by a map of symbol to twig.
> Yes, the span contains the complete AST of the whole core.
This is a very different approach from most typed languages,
which compute function signatures. To infer the product of an
arm, we retrace the code in theory, but cache in practice.
### Arms are computed attributes
How do we use a core? Remember that Nock is a function
```
Nock(subject formula) -> product
```
To activate a core, we pull one formula from the battery, and
execute with the whole core as the subject. Coincidentally,
Nock has one macro instruction, `9`, that does just this.
So the formula defines an arbitrary function on the core. The
name of this function (as defined in the twig map) is a computed
attribute, or *arm*.
> Is a core an object? Not quite, because an arm is not a method.
Methods in an OO language have arguments. Arms are functions
only of the payload. (A method in Hoon is an arm that produces a
gate, which is another core -- but we're getting too far ahead.)
However, the battery does look a lot like a classic "vtable."
### Arms and wing resolution
It might be a good time to brush up on your [chapter 1](1-twigs).
The wing resolution algorithm gets a little more complicated.
Hoon overloads computed attributes (arms) and literal attributes
(legs) in the same namespace. A label in a wing may refer to
either. when searching a core, we look for a matching arm. If
we find it we're done. If we don't, or if a `^` mark makes us
skip, we search into the payload.
Only the last limb in the wing can activate an arm. If a name
resolves to a core arm, but it's not the last limb in the wing,
the arm produces the core itself. Similarly, when the wing is
not an access but a mutation, the arm refers to the core. Only
the end of the wing is activated.
> Suppose `foo` is a core. `bar` is an arm on foo. Then `bar.foo`
computes the `bar` arm. Perhaps the product is another core.
Even if `moo` is an arm in this new core, `bar.foo`, the wing
`moo.bar.foo` does not compute `moo` on the core `bar.foo`.
Instead, it looks for `moo` within the payload of the core `foo`.
(You're looking for `moo:bar.foo`, ie, `=>(bar.foo moo)`.)
Does this sound too tricky? Hopefully not, but it's about the
most complicated semantic rule you'll find in Hoon.
## Increment with a core
Keeping our two-line boilerplate, let's increment with a core:
```
=< inc
|%
++ inc
+(arg)
--
~tasfyn-partyv:dojo/sandbox> +test 42
43
```
What's going on? We used the `|%` rune ("barcen") to produce a
core. (There are a lot of runes which create cores; they all
start with `|`, and are basically macros that turn into `|%`.)
The payload of a core produced with `|%` is the subject with
which `|%` is compiled. We might say that `|%` wraps a core
around its subject. In this case, the subject of the `|%`,
and thus payload, is our `arg=@ud` argument.
Then we used this core as the subject of the simple wing `inc`.
> Remember that `=<(a b)` is just `=>(b a)`. The core is heavy
and `inc` is light, so we use `=<` to put the heavy part last.
The prettyprinter can even print a core, sort of. Take out the
`=< inc`:
```
|%
++ inc
+(arg)
--
~tasfyn-partyv:dojo/sandbox> +test 42
<1.bgq arg=42>
~tasfyn-partyv:dojo/sandbox> ? +test 42
<1.bgq arg=@ud>
<1.bgq arg=42>
```
In this notation, `1` means the number of arms in the core, `bgq`
is a very short fingerprint, and `arg=42` is the payload (and
`arg=@ud` is the payload span).
> Cores can be large and complex, and we obviously can't render all
the data in them, either when printing a type or a value. At
some point, you'll probably make the mistake of printing a big
core, maybe even the whole kernel, as an untyped noun. Just
press ^C.
## Adding a counter
To decrement, we need to count up to the argument. So we need a
counter in our subject, because where else would it go?
Let's change the subject to add a counter, `pre`:
```
=> [pre=0 .]
=< inc
|%
++ inc
+(arg)
--
~tasfyn-partyv:dojo/sandbox> +test 42
43
```
Once again, `.` is the whole subject, so we're wrapping it in a
cell whose head is `pre=0`. This doesn't change the way we use
`arg`, even though it's one level deeper in the subject tree.
Let's look at the subject again:
```
=> [pre=0 .]
.
~tasfyn-partyv:dojo/sandbox> +test 42
[pre=0 arg=42]
~tasfyn-partyv:dojo/sandbox> ? +test 42
[pre=@ud arg=@ud]
[pre=0 arg=42]
```
There's a less cluttered way to write `=>([a .] b)`. In wide
mode, `=+(a b)`. A tall example:
```
=+ pre=0
.
~tasfyn-partyv:dojo/sandbox> +test 42
[pre=0 arg=42]
```
This rune `=+`, "tislus", `%tsls`, is of course the "variable
declaration" we saw in chapter 2.
## We actually decrement
Now we can write our actual decrement program, combining the
features we've explored above:
```
=+ pre=0
=< dec
|%
++ dec
?: =(arg +(pre))
pre
dec(pre +(pre))
--
~tasfyn-partyv:dojo/sandbox> +test 42
41
```
`=(a b)` is an irregular form of `.=(a b)`, ie, "dottis" or the
noun `[%dtts a b]`. Likewise, `+(a)` is `.+(a)`, ie, "dotlus"
or `[%dtls a]`.
`?:`, "wuttis", `%wtts`, does exactly what it does in C.
The real action is in `dec(pre +(pre))`. We saw this same
mutation form in chapter 1. It's an irregular form of the `%=`
rune, "centis", `%cnts`.
Here, of course, we're computing an arm of a mutated core. We're
recomputing the loop arm, `dec`, against a new core with an
incremented `pre` leg. Basically, everything interesting in Hoon
happens when you compute an arm of a mutated core.
The whole program, using only regular forms, wide and tall:
```
=+ ^=(pre 0)
=< dec
|%
++ dec
?: .=(arg .+(pre))
pre
%= dec
pre .+(pre)
==
--
~tasfyn-partyv:dojo/sandbox> +test 42
41
```
A good illustration of why we need irregular forms.
## Progress
Now we've actually done something useful. Well, if you count
O(n) decrement as something useful.
We've actually seen most of the major tools in Hoon's toolbox,
just in a super-minimalist selection. But we'll need a few more
runes to get to something that looks like real programming.
For instance, we have a decrement algorithm, but we don't have a
decrement *function* - in the Hoon sense of the word, anyway. We
don't see `(dec arg)` in this code. That'll be the next chapter.