mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-23 23:12:04 +03:00
351 lines
9.9 KiB
Markdown
351 lines
9.9 KiB
Markdown
---
|
|
next: false
|
|
sort: 3
|
|
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.
|