Merge remote-tracking branch 'curtis/newdoc'

This commit is contained in:
vere 2015-11-03 21:58:24 +00:00
commit c9d45b4d72
16 changed files with 632 additions and 502 deletions

View File

@ -7,8 +7,9 @@ sort: 2
# Developer documentation # Developer documentation
Urbit has three programming layers: Nock (combinator nano-VM), Urbit has three programming layers: [Nock](dev/nock) (combinator nano-VM),
Hoon (strict functional language), and Arvo (functional OS). [Hoon](dev/hoon) (strict functional language), and [Arvo](dev/arvo) (functional
OS).
To code in Urbit, the least you need to learn is Hoon, plus a To code in Urbit, the least you need to learn is Hoon, plus a
little bit of Arvo. Nock is a sort of functional assembly little bit of Arvo. Nock is a sort of functional assembly

View File

@ -7,8 +7,7 @@ sort: 3
# Arvo # Arvo
Arvo is a functional operating system. Arvo is a functional operating system. But hopefully you knew that! Sorry,
please watch this space for actual documentation.
Watch this space for actual documentation.
</div> </div>

View File

@ -10,6 +10,6 @@ sort: 2
Hoon is a strict, typed, pure functional language. Hoon is a strict, typed, pure functional language.
Watch this space for actual documentation. We're still updating the docs; start with the tutorial, ["Hoon 101"](hoon/tutorial).
</div> </div>

View File

@ -1,4 +0,0 @@
Tutorials
=========
<list dataPreview="true" titlesOnly="true"></list>

View File

@ -0,0 +1,10 @@
---
logo: black
title: Hoon 101
sort: 2
---
Welcome to Hoon 101! This tutorial is still under construction;
check back later for more installments.
<list></list>

View File

@ -1,232 +0,0 @@
# Hoon 0: introduction
Hoon is a strict, higher-order typed pure-functional language.
Why Hoon? On the one hand, typed functional languages are known
for a particularly pleasant phenomenon: once your code compiles,
it's quite likely to work. On the other hand, most typed
functional languages are influenced by advanced mathematics.
As Barbie once put it, math class is hard.
Hoon is a typed FP language for the common street programmer.
Well-written Hoon is as concrete and data-oriented as possible.
The less functional magic you use, the better. One Haskell
hacker described Hoon as "imperative programming in a functional
language." He didn't mean this as a compliment, but we choose to
take it as one.
Moreover, one task of a type system in network computing is
marshalling typed data on the sender, and validating untrusted
data on the receiver. Hoon is very good at this task, which in
most typed languages is an afterthought at best.
The main disadvantage of Hoon is that its syntax and semantics
are unfamiliar. The syntax will remind too many of Perl, but
like most human languages (and unlike Perl) it combines a regular
core structure with irregular variations. Its semantic
complexity is bounded by the fact that the compiler is only 2000
lines of Hoon (admittedly an expressive language). Most peoples'
experience is that Hoon is much easier to learn than it looks.
## Nouns: data made boring
A noun is an atom or a cell. An atom is any unsigned integer. A
cell is an ordered pair of nouns.
The noun is an intentionally boring data model. Nouns (at least,
nouns in Urbit) don't have cycles (although a noun implementation
should take advantage of acyclic graph structure). Noun
comparison is always by value (there is no way for the programmer
to test pointer equality). Nouns are strict; there is no such
thing as an infinite noun. And, of course, nouns are immutable.
So there's basically no way to have any real fun with nouns.
For language historians, nouns are Lisp's S-expressions, minus a
lot of hacks, tricks, and features that made sense 50 years ago.
In particular, because atoms are not tagged (an atom can encode a
string, for instance), nouns work best with a static type system.
How do you print an atom if you don't know whether it's a string
or a number? You can guess, but...
## A type system for nouns
So learning nouns in practice involves learning them with a type
system that makes them usable. Fortunately, we have that.
One obstacle to learning Hoon is that it has two quite distinct
concepts that might equally be called a "type." Worse, most
other typed functional languages are mathy and share a basically
mathematical concept of "type." We can't avoid using the T-word
occasionally, but it has no precise meaning in Hoon and can be
extremely confusing.
Hoon's two kinds of "type" are `span` and `mold`. A span is both
a constructively defined set of nouns, and a semantic convention
for users in that set. A `mold` is a function whose range is
some useful span. A mold is always idempotent (for any noun x,
`f(x)` equals `f(f(x))`), and its domain is any noun.
(One way to explain this is that while a span is what most
languages call a "type," Hoon has no way for the programmer to
express a span directly. Instead, we use inference to define it
as the range of a function. This same function, the mold, can
also be used to validate or normalize untrusted, untyped data --
a common problem in modern programming.)
(Hoon's inference algorithm is somewhat dumber than the
unification algorithms (Hindley-Milner) used in most typed
functional languages. Hoon reasons only forward, not backward.
It needs more manual annotations, which you usually want anyway.
Otherwise, it gets more or less the same job done.)
## Let's make some nouns
This stuff isn't even slightly hard. Let's make a noun:
```
~tasfyn-partyv:dojo> 42
```
You'll see the expression you entered, then the resulting value:
```
> 42
42
```
Let's try a different value:
```
~tasfyn-partyv:dojo> 0x2a
```
You'll see:
```
> 0x2a
0x2a
```
`42` and `0x2a` are actually *the same noun*, because they're the
same number. But we don't just have the noun to print - we have
a `[span noun]` cell (sometimes called a `vase`).
As you recall, a span defines a set of nouns and a semantic
interpretation. As sets, both spans here are "any number". But
semantically, `42` has a decimal span and `0x2a` hexadecimal, so
they print differently.
(It's important to note that Hoon is a statically typed language.
We don't work with vases unless we're dynamically compiling code,
which is of course what we're doing here in the shell. Dynamic
type is static type compiled at runtime.)
Finally, let's make some cells. Try these on your own ship:
```
~tasfyn-partyv:dojo> [42 0x2a]
~tasfyn-partyv:dojo> [42 [0x2a 420]]
~tasfyn-partyv:dojo> [42 0x2a 420]
```
We observe that cells associate right: `[a b c]` is just another
way of writing `[a [b c]]`.
Also, Lisp veterans beware: Hoon `[a b]` is Lisp `(a . b)`, Lisp
`(a b)` is Hoon `[a b ~]`(`~` represents nil, with a value of atom `0`). Lisp and Hoon are both pair-oriented
languages down below, but Lisp has a layer of sugar that makes it
look list-oriented. Hoon loves its "improper lists," ie, tuples.
## Looking at spans
What are these mysterious spans? We can see them with the `?`
prefix, which prints the span along with the result. Moving to
a more compact example format:
```
~tasfyn-partyv:dojo> ? 42
@ud
42
~tasfyn-partyv:dojo> ? 0x2a
@ux
0x2a
```
`@ud` and `@ux` stand for "unsigned decimal" and "unsigned hex,"
obviously. But what is this syntax?
We only derive spans through inference. So there's no language
syntax for a span. We have to be able to print spans, though, if
only for debugging and diagnostics. `@ud` is an print-only
syntax. (In this case it happens to be the same as the `mold`
syntax, but that's just a coincidence.)
## Looking at spans, part 2
A good way to teach yourself to think in nouns is to look not at
the prettyprinted span, but at the actual noun it's made of.
Since everything in Hoon is a noun, a span is a noun too. When
we use `??` rather than `?` as a prefix, we see the noun:
```
~tasfyn-partyv:dojo> ?? 42
[%atom %ud]
42
~tasfyn-partyv:dojo> ?? [42 0x2a]
[%cell [%atom %ud] [%atom %ux]]
[42 0x2a]
```
What is this `%atom` notation? Is it a real noun? Can anyone
make one?
```
~tasfyn-partyv:dojo> %atom
%atom
~tasfyn-partyv:dojo> %foo
%foo
~tasfyn-partyv:dojo> [%foo %bar]
[%foo %bar]
```
What if we look at the span?
```
~tasfyn-partyv:dojo> ? %foo
%foo
%foo
~tasfyn-partyv:dojo> ?? %foo
[%cube 7.303.014 %atom %tas]
%foo
```
This takes a little bit of explaining. First of all, `7.303.014`
is just the German (and Urbit) way of writing `7,303,014`, or the
hexadecimal number `0x6f.6f66`, or the string "foo" as an
unsigned integer. (It's much easier to work with large integers
when the digits are grouped.) Second, remembering that cells
nest right, `[%cube 7.303.014 %atom %tas]` is really `[%cube
7.303.014 [%atom %tas]]`.
A `%cube` span is a constant -- a set of one noun, the atom
`7.303.014`. But we still need to know how to print that noun.
In this case, it's an `[%atom %tas]`, ie, a text symbol.
Cubes don't have to be symbols -- in fact, we can take the
numbers we've just been using, and make them constants:
```
~tasfyn-partyv:dojo> %42
%42
~tasfyn-partyv:dojo> ? %42
%42
%42
~tasfyn-partyv:dojo> ?? %42
[%cube 42 %atom %ud]
%42
```
## Our first mold
After seeing a few span examples, are we ready to describe the
set of all spans with a Hoon mold? Well, no, but let's try it
anyway. Ignore the syntax (which we'll explain later; this is a
tutorial, not a reference manual), and you'll get the idea:
```
++ span
$% [%atom @tas]
[%cell span span]
[%cube * span]
==
```
This mold is not the entire definition of `span`, just the cases
we've seen so far. In English, a valid span is either:
- a cell with head `%atom`, and tail some symbol.
- a cell with head `%cell`, and tail some pair of spans.
- a cell with head `%cube`, and tail a noun-span pair.
The head of a span is essentially the tag in a variant record,
a pattern every programming language has. To use the noun, we
look at the head and then decide what to do with the tail.

View File

@ -0,0 +1,272 @@
---
title: Hoon 101.0: nouns, spans, and molds
sort: 0
next: true
---
# Hoon 101.0: nouns, spans and molds
Hoon is a strict, higher-order typed pure-functional language.
Why Hoon? Typed functional languages are known for a pleasant
phenomenon: once your code compiles, it's quite likely to work.
But most typed functional languages are conceptually dependent on
abstract advanced math, and difficult to understand without it.
Hoon is a typed FP language for the common street programmer.
Well-written Hoon is as concrete and data-oriented as possible.
The less functional magic you use, the better. But the magic is
there, mostly, if you need it.
The main disadvantage of Hoon is that its syntax and semantics
are unfamiliar. The syntax will remind too many of Perl, but
like most human languages (and unlike Perl) it combines a regular
core structure with irregular variations. And Hoon's semantic
is bounded by the size of the compiler: type inference plus code
generation are 2000 lines of Hoon. Most peoples' experience is
that the language is much easier to learn than it looks. Not
that it looks easy!
> The name "Hoon" is from the Wallace Stevens poem, _Tea at the
Palaz of Hoon_. It also means "hooligan" in Australian.
## Nouns: data made boring
A noun is an atom or a cell. An atom is any unsigned integer. A
cell is an ordered pair of nouns.
The noun is an intentionally boring data model. Nouns don't have
cycles (although a noun implementation should take advantage of
acyclic graph structure). Noun comparison is always by value
(there is no way for the programmer to test pointer equality).
Nouns are strict; there is no such thing as an infinite noun.
And, of course, nouns are immutable. There's basically no way to
have any real fun with nouns.
> Nouns are Lisp's S-expressions, minus a lot of hacks, tricks,
and features that made sense 50 years ago. In particular,
because atoms are not tagged (an atom can encode a string, for
instance), nouns depend on a static type system at a higher
layer. How do you print an atom if you don't know whether it's a
string or a number?
## A type system for nouns
One obstacle to learning Hoon is that it has two quite distinct
concepts that might equally be called a "type." Worse, most
other typed functional languages are mathy and share a basically
mathematical concept of "type." Hoon does not have this concept
at all. We can't avoid using the T-word occasionally, but it has
no precise meaning in Hoon and can be extremely confusing.
Hoon's two kinds of "type" are `span` and `mold`. A span is both
a constructively defined set of nouns, and a semantic convention
for users in that set. A `mold` is a function whose range is
some useful span. A mold is always idempotent (for any noun `x`,
`f(x)` equals `f(f(x))`), and its domain is any noun.
One way to explain this is that while a span is what most
languages call a "type," Hoon has no syntax for the programmer to
define a span directly. Instead, we use inference to define it
as the range of a mold function. This mold can also be used to
validate or normalize untrusted, untyped data -- a common problem
in modern programming, because networks.
Hoon's inference algorithm is dumber than the unification
algorithms (Hindley-Milner) used in most typed functional
languages. Hoon thinks only forward, not backward. Eg, Haskell
can infer the result type of a function from its argument
(forward), or the argument type from the result (backward).
Hoon can do the first but not the second.
So Hoon needs more manual typecasts, which you usually want
anyway for prosaic software-engineering reasons. Otherwise its
typesystem solves more or less the same job, including
pattern-matching, genericity / typeclasses, etc.
> Sending a noun over the network is a good example of why Hoon
is different. In a normal modern language, you serialize and
deserialize a data type by extending your type to implement a
serialization interface. In Hoon, any value is just a noun, so
we have one function (`jam`) that converts any noun to an atom,
and another (`cue`) that is its inverse. To validate, the
receiver runs its own mold on the cued noun, and we've sent typed
data over the network without any attack surface (except `jam`
and `cue`, which fit on a page). No custom serialization methods
are required, and the mold itself is never sent; protocol
agreement is out of band.
## Let's make some nouns
Nouns aren't even slightly hard. Let's make a noun:
```
~tasfyn-partyv:dojo> 42
```
You'll see the expression you entered, then the result:
```
> 42
42
```
Let's try a different value:
```
~tasfyn-partyv:dojo> 0x2a
```
You'll see:
```
> 0x2a
0x2a
```
`42` and `0x2a` are actually *the same noun*, because they're the
same number. But we don't just have the noun to print - we have
a `[span noun]` cell (sometimes called a `vase`).
As you recall, a span defines a set of nouns and a semantic
interpretation. As sets, both spans here are "any number". But
semantically, `42` has a decimal span and `0x2a` hexadecimal, so
they print differently.
> It's important to remember that Hoon is a statically typed language.
We don't work with vases unless we're dynamically compiling code,
which is of course what we're doing here in the dojo. In Hoon,
dynamic type equals static type plus runtime compilation.
Let's make some cells. Try these on your own urbit:
```
~tasfyn-partyv:dojo> [42 0x2a]
~tasfyn-partyv:dojo> [42 [0x2a 420]]
~tasfyn-partyv:dojo> [42 0x2a 420]
```
We observe that cells associate right: `[a b c]` is just another
way of writing `[a [b c]]`.
> Lisp veterans beware: Hoon `[a b]` is Lisp `(a . b)`, Lisp
`(a b)` is Hoon `[a b ~]`(`~` represents nil, with a value of
atom `0`). Lisp and Hoon are both pair-oriented languages down
below, but Lisp has a layer of sugar that makes it look
list-oriented. Hoon loves its "improper lists," ie, tuples.
## Looking at spans
What are these mysterious spans? We can see them with the `?`
prefix, which prints the span along with the result. Moving to
a more compact example format:
```
~tasfyn-partyv:dojo> ? 42
@ud
42
~tasfyn-partyv:dojo> ? 0x2a
@ux
0x2a
```
`@ud` and `@ux` stand for "unsigned decimal" and "unsigned hex,"
obviously.
> What is this span syntax? We only derive spans through
inference. So there's no parsing grammar for a span. We have to
be able to print spans, if only for debugging and diagnostics,
but the syntax is output-only. As in this case, it often looks
like the `mold` syntax, but the two are at opposite ends of the
type food chain.
## Looking at spans, part 2
Good style in Hoon is concrete style. When a Hoon programmer
defines an abstract semantic value in terms of a noun, we rarely
put a conceptual layer of abstraction between value and noun. We
think of the semantic value as an interpretation of the
concrete noun, and often we just think of the noun.
With the `?` command, we *do* use an abstract layer, by printing
our span noun in a custom syntax. But we can also look at the
span noun directly, with the `??` command.
```
~tasfyn-partyv:dojo> ?? 42
[%atom %ud]
42
~tasfyn-partyv:dojo> ?? [42 0x2a]
[%cell [%atom %ud] [%atom %ux]]
[42 0x2a]
```
What is this `%atom` syntax? Is it a real noun? Can anyone
make one?
```
~tasfyn-partyv:dojo> %atom
%atom
~tasfyn-partyv:dojo> %foo
%foo
~tasfyn-partyv:dojo> [%foo %bar]
[%foo %bar]
```
What's the span of one of these symbols?
```
~tasfyn-partyv:dojo> ? %foo
%foo
%foo
~tasfyn-partyv:dojo> ?? %foo
[%cube 7.303.014 [%atom %tas]]
%foo
```
This takes a little bit of explaining. `7.303.014` is just the
Urbit (and German) way of writing the English number `7,303,014`,
or the Urbit hex number `0x6f.6f66`, or the string "foo" as an
unsigned integer with least-significant byte first.
A `%cube` span is a constant -- a set of one noun, the atom
`7.303.014`. But we still need to know how to print that noun.
In this case, it's an `[%atom %tas]`, ie, a text symbol.
Cubes don't have to be symbols -- in fact, we can take the
numbers we've just been using, and make them constants:
```
~tasfyn-partyv:dojo> %42
%42
~tasfyn-partyv:dojo> ? %42
%42
%42
~tasfyn-partyv:dojo> ?? %42
[%cube 42 [%atom %ud]]
%42
```
> Spans are an exception to the concrete style, because we use
"manual laziness" to define recursive structures. A recursive
span contains Hoon code which is evaluated to apply it. In
practice, it often contains the entire Urbit kernel, so you
wouldn't want to try to print it in the dojo. If you find
`??` taking a weirdly long time, this may have happened; just
press ^C.
## Our first mold
After seeing a few span examples, are we ready to describe the
set of all spans with a Hoon mold? Well, no, but let's try it
anyway. Ignore the syntax (which we'll explain later; this is a
tutorial, not a reference manual), and you'll get the idea:
```
++ span
$% [%atom p=@tas]
[%cell p=span q=span]
[%cube p=* q=span]
==
```
This mold is not the entire definition of `span`, just the cases
we've seen so far. In English, a valid span is either:
- a cell with head `%atom`, and tail some symbol.
- a cell with head `%cell`, and tail some pair of spans.
- a cell with head `%cube`, and tail a noun-span pair.
The head of a span is essentially the tag in a variant record,
a pattern every programming language has. To use the span, we
look at the head and then decide what to do with the tail.
> A conventional naming strategy for simple, self-explaining
structures is to name the legs of a tuple `p`, `q`, `r`, `s` and
`t`. If you get all the way to `t`, your noun is probably not
simple or self-explaining; meaningful names are recommended.
Believe it or not, at this point we understand nouns completely.
We don't understand spans and molds completely, but we get the
basics. In the next chapter, we'll see how Hoon expressions
(twigs) turn one noun into another.

View File

@ -1,229 +0,0 @@
# Hoon 1: twigs and legs
In the last chapter we learned how to make nouns. In this
chapter we'll start programming a little.
## Nock for Hoon programmers
Hoon compiles itself to a pico-interpreter called Nock. This
isn't the place to explain Nock (which is to Hoon much as
assembly language is to C), but Nock is just a way to express a
function as a noun.
Specifically, you can think of Nock as a (Turing-complete)
interpreter shaped like (pseudocode):
```
Nock(subject formula) => product
```
Your function is the noun `formula`. The input to the function
is the noun `subject`. The output is `product`. If something
about this seems complicated or even interesting, you may be
misunderstanding it.
## From Hoon to Nock
The Hoon parser turns an source expression (even one as simple as
`42` from the last chapter) into a noun called a `twig`. If you
know what an AST is, a twig is an AST. (If you don't know what
an AST is, it's not worth the student loans.)
To simplify slightly, the Hoon compiler is shaped like:
```
Hoon(subject-span function-twig) => [product-span formula-nock]
```
Hoon, like Nock, is a *subject-oriented* language - your twig is
always executed against one input noun, the subject. For any
subject noun in `subject-span`, the compiler produces a Nock
formula that computes `function-twig` on that subject, and a
`product-span` that is the span of the product.
(Pretty much no other language works this way. In a normal
language, your code is executed against a scope, stack, or other
variable context, which may not even be a regular user-level
value. This change is one of the hardest things to understand
about Hoon, mostly because it's hard to stay convinced that
subject-oriented programming is as straightforward as it is.)
## From constants to twigs
In the last chapter we were entering degenerate twigs like `42`.
Obviously this doesn't use the subject at all.
Let's use the dojo variable facility (this is *not* Hoon syntax,
just a dojo command) to make a test subject:
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] [6 7]]
```
We can evaluate twigs against this subject with the Hoon `:`
syntax (`a:b` uses the product of `b` as the subject of `a`).
```
~tasfyn-partyv:dojo> 42:test
42
```
## Tree addressing
The simplest twigs produce a subtree, or "leg", of the subject.
A cell, of course, is a binary tree. The very simplest twig is
`.`, which produces the root of the tree - the whole subject:
```
~tasfyn-partyv:dojo> .:test
[[[8 9] 5] 6 7]
```
(If you're wondering why `[6 7]` got printed as `6 7`, remember
that `[]` associates to the right.)
Hoon has a simple tree addressing scheme (inherited from Nock):
the root is `1`, the head of `n` is `2n`, the tail is `2n+1`.
The twig syntax is `+n`. Hence:
```
~tasfyn-partyv:dojo> +1:test
[[[8 9] 5] 6 7]
```
Our example is a sort of Hoon joke, not very funny:
```
~tasfyn-partyv:dojo> +2:test
[[8 9] 5]
~tasfyn-partyv:dojo> +3:test
[6 7]
~tasfyn-partyv:dojo> +4:test
[8 9]
~tasfyn-partyv:dojo> +5:test
5
~tasfyn-partyv:dojo> +6:test
6
~tasfyn-partyv:dojo> +7:test
7
```
And so on. An instinct for binary tree geometry develops over
time as you use the system, rather the way most programmers
learn to do binary math.
## Femur syntax
A "femur" is an alternative syntax for a tree address. The femur
syntax creates a recognizable geometric shape by alternating
between two head/tail pairs, read left to right: `-` and `+`,
`<` and `>`.
Thus `-` is `+2`, `+` is `+3`, `+<` is `+6`, `->` is `+5`, `-<+`
is `+9`, etc. The decimal numbers are distracting, whereas the
glyph string binds directly to the tree geometry as you learn it.
We actually almost never use the decimal tree geometry syntax.
## Simple faces
But it would be pretty tough to program in Hoon if explicit
geometry was the only way of getting data out of a subject.
Let's introduce some new syntax:
```
~tasfyn-partyv:dojo> foo=42
foo=42
~tasfyn-partyv:dojo> ? foo=42
foo=@ud
foo=42
~tasfyn-partyv:dojo> ?? foo=42
[%face %foo %atom %ud]
foo=42
```
To extend our `++span` mold:
```
++ span
$% [%atom @tas]
[%cell span span]
[%cube * span]
[%face @tas span]
==
```
The `%face` span wraps a label around a noun. Then we can
get a leg by name. Let's make a new dojo variable:
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] foo=[6 7]]
```
The syntax is what you might expect:
```
~tasfyn-partyv:dojo> foo:test
[6 7]
```
Does this do what you expect it to do?
```
~tasfyn-partyv:dojo> +3:test
foo=[6 7]
~tasfyn-partyv:dojo> ? +3:test
foo=[@ud @ud]
foo=[6 7]
~tasfyn-partyv:dojo> ?? +3:test
[%face %foo %cell [%atom %ud] %atom %ud]
foo=[6 7]
```
## Interesting faces; wings
Again, you're probably used to name resolution in variable scopes
and flat records, but not in trees. (Partly this is because the
tradition in language design is to eschew semantics that make it
hard to build simple symbol tables, because linear search of a
big tree is a bad idea on '80s hardware.)
Let's look at a few more interesting face cases. First, suppose
we have two cases of `foo`?
```
~tasfyn-partyv:dojo> =test [[foo=[8 9] 5] foo=[6 7]]
~tasfyn-partyv:dojo> foo:test
[8 9]
```
In the tree search, the head wins. We can overcome this with a
`^` prefix, which tells the search to skip its first hit:
```
~tasfyn-partyv:dojo> =test [[foo=[8 9] 5] foo=[6 7]]
~tasfyn-partyv:dojo> ^foo:test
[6 7]
```
`^^foo` will skip two foos, `^^^foo` three, up to `n`.
But what about nested labels?
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] foo=[6 bar=7]]
~tasfyn-partyv:dojo> bar:test
/~tasfyn-partyv/home/~2015.9.16..21.40.21..1aec:<[1 1].[1 9]>
-find-limb.bar
find-none
```
It didn't seem to like that. We'll need a nested search:
```
~tasfyn-partyv:dojo> bar.foo:test
7
```
`bar.foo` here is a `wing`, a search path in a noun. Note that
the wing runs from left to right, ie, the opposite of most
languages: `bar.foo` means "bar inside foo."
Each step in a wing is a `limb`. A limb can be a tree address,
like `+3` or `.`, or a label like `foo`. We can combine them in
one wing:
```
~tasfyn-partyv:dojo> bar.foo.+3:test
7
```
## Mutation
Well, not really. We can't modify nouns; the concept doesn't
even make sense in Hoon. Rather, we build new nouns which are
(logical -- the pointers are actually shared) copies of old ones,
with changes.
Let's build a "mutated" copy of our test noun:
```
~tasfyn-partyv:dojo> test
[[[8 9] 5] foo=[6 bar=7]]
~tasfyn-partyv:dojo> test(foo 42)
[[[8 9] 5] foo=42]
~tasfyn-partyv:dojo> test(+8 %eight, bar.foo [%hello %world])
[[[%eight 9] 5] foo=[6 [%hello %world]]]
```
As we see, there's no obvious need for the mutant noun to be
shaped anything like the old noun. They're different nouns.
At this point, you have a simplified but basically sound idea of
how Hoon builds and manages nouns. Next, it's time to do some
programming.

View File

@ -0,0 +1,281 @@
---
title: Hoon 101.1: twigs and legs
sort: 1
hide: true
next: false
---
# Hoon 101.1: twigs and legs
In the last chapter we learned how to make nouns. In this
chapter we'll start programming a little.
Reminder: we nest large digressions in curly braces. If you see
a {paragraph} or two, assume it's of interest to language nerds
only, and "guaranteed not on the test."
## Nock for Hoon programmers
Hoon compiles itself to a pico-interpreter called Nock, a
combinator algebra defined in 200 words. This isn't the place to
explain Nock (which is to Hoon much as assembly language is to
C), but Nock is just a way to express a function as a noun.
Specifically, you can think of Nock as a (Turing-complete)
interpreter shaped like (pseudocode):
```
Nock(problem) => product
```
This `problem` is always a cell `[subject formula]`. The
function is `formula`. The input to the function is the noun
`subject`. The output is the noun `product`.
(Why is Nock `[subject formula]` rather than `[formula subject]`?
Or, to use more familiar terminology, why `[argument function]`
rather than `[function argument]`? For no good reason, but it
doesn't really matter in practice.)
## From Hoon to Nock
The Hoon parser turns an source expression (even one as simple as
`42` from the last chapter) into a noun called a `twig`. If you
know what an AST is, a twig is an AST. (If you don't know what
an AST is, you probably don't have any student loans.)
To simplify slightly, the Hoon compiler is shaped like:
```
Hoon(subject-span function-twig) => [product-span formula-nock]
```
Hoon, like Nock, is a *subject-oriented* language. Your code is
always executed against one input noun, the subject. For any
subject noun in `subject-span` (ie, argument type), the compiler
produces a Nock formula that computes `function-twig` on that
subject, and a `product-span` that is the span of the product
(ie, result type).
{This is really a nontrivial difference. In a normal,
non-subject-oriented language, your code executes against a
scope, stack, environment, or other variable context, probably
not even a regular user-level value. For ordinary coders, "SOP"
is one of the hardest things to understand about Hoon; for some
reason, your brain keeps wanting the interpreter to be more
complicated. There is of course a stack in a Nock interpreter,
but solely for reduction state; actually, you can build a Nock
that uses the C stack only, but still provides perfect TCO.}
## From constants to twigs
In the last chapter we were entering degenerate twigs like `42`.
Obviously a numeric constant doesn't use the subject at all, so
it's not a very interesting example of SOP.
Let's use the dojo variable facility (this is *not* Hoon syntax,
just a dojo command) to make a test subject:
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] [6 7]]
```
The `=test` command tells the dojo to rearrange its stock subject
to include this `test` noun. Let's check that it's there:
```
~tasfyn-partyv:dojo> test
[[[8 9] 5] 6 7]
```
{If you're wondering why `[6 7]` got printed as `6 7`, remember
that `[]` associates to the right.}
We want to use `test`, this harmless little noun, as the subject
for some equally harmless twigs. We can do this with the `:`
syntax, which composes twigs in the functional sense. The twig
`a:b` uses the product of twig `b` as the subject of twig `a`:
```
~tasfyn-partyv:dojo> 42:test
42
~tasfyn-partyv:dojo> 42:420
42
```
## Tree addressing
The simplest twigs produce a subtree, or "leg", of the subject.
A cell, of course, is a binary tree. The very simplest twig is
`.`, which produces the root of the tree - the whole subject:
```
~tasfyn-partyv:dojo> .:test
[[[8 9] 5] 6 7]
```
Like human languages, Hoon is full of irregular abbreviations.
The `.` syntax is a shorthand for `+1`:
```
~tasfyn-partyv:dojo> +1:test
[[[8 9] 5] 6 7]
```
Hoon has a simple tree addressing scheme (inherited from Nock):
the root is `1`, the head of `n` is `2n`, the tail is `2n+1`.
The twig syntax for a tree address is `+n`.
In our example noun, each leaf is its own tree address:
```
~tasfyn-partyv:dojo> +2:test
[[8 9] 5]
~tasfyn-partyv:dojo> +3:test
[6 7]
~tasfyn-partyv:dojo> +4:test
[8 9]
~tasfyn-partyv:dojo> +5:test
5
~tasfyn-partyv:dojo> +6:test
6
~tasfyn-partyv:dojo> +7:test
7
```
{An instinct for binary tree geometry develops over time as you
use the system, rather the way most programmers learn to do
binary math. No, really.}
## Lark syntax
This alternative syntax for a tree address maps noun geometry
directly to a glyph, skipping numbers. Lark syntax creates a
recognizable geometric shape by alternating between two head/tail
pairs, read left to right: `-` and `+`, `<` and `>`.
Thus `-` is `+2`, `+` is `+3`, `+<` is `+6`, `->` is `+5`, `-<+`
is `+9`, etc.
{Why lark syntax? Code full of numbers is ugly and distracting,
and looks like hardcoded constants. We actually almost never use
the `+` syntax.}
## Simple faces
Tree addressing is cool, but it would be pretty tough to program
in Hoon if it was the only way of getting data out of a subject.
Let's introduce some new syntax:
```
~tasfyn-partyv:dojo> foo=42
foo=42
~tasfyn-partyv:dojo> ? foo=42
foo=@ud
foo=42
~tasfyn-partyv:dojo> ?? foo=42
[%face %foo [%atom %ud]]
foo=42
```
To extend our `++span` mold:
```
++ span
$% [%atom p=@tas]
[%cell p=span p=span]
[%cube p=* q=span]
[%face p=@tas q=span]
==
```
The `%face` span wraps a label around a noun. Then we can
get a leg by name. Let's make a new dojo variable:
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] foo=[6 7]]
```
The syntax is what you might expect:
```
~tasfyn-partyv:dojo> test
[[[8 9] 5] foo=[6 7]]
~tasfyn-partyv:dojo> foo:test
[6 7]
```
Does this do what you expect it to do?
```
~tasfyn-partyv:dojo> +3:test
foo=[6 7]
~tasfyn-partyv:dojo> ? +3:test
foo=[@ud @ud]
foo=[6 7]
~tasfyn-partyv:dojo> ?? +3:test
[%face %foo [%cell [%atom %ud] [%atom %ud]]]
foo=[6 7]
```
## Interesting faces; wings
Again, you're probably used to name resolution in variable scopes
and flat records, but not in trees. (Partly this is because the
tradition in language design is to eschew semantics that make it
hard to build simple symbol tables, because linear search of a
nontrivial tree is a bad idea on '80s hardware.}
Let's look at a few more interesting face cases. First, suppose
we have two cases of `foo`?
```
~tasfyn-partyv:dojo> =test [[foo=[8 9] 5] foo=[6 7]]
~tasfyn-partyv:dojo> foo:test
[8 9]
```
In the tree search, the head wins. We can overcome this with a
`^` prefix, which tells the search to skip its first hit:
```
~tasfyn-partyv:dojo> ^foo:test
[6 7]
```
`^^foo` will skip two foos, `^^^foo` three, *ad infinitum*.
But what about nested labels?
```
~tasfyn-partyv:dojo> =test [[[8 9] 5] foo=[6 bar=7]]
~tasfyn-partyv:dojo> bar:test
/~tasfyn-partyv/home/~2015.9.16..21.40.21..1aec:<[1 1].[1 9]>
-find-limb.bar
find-none
```
We can't search *through* a label. If we want to get our `bar`
out, we need to search *into* it:
```
~tasfyn-partyv:dojo> bar.foo:test
7
```
`bar.foo` is what we call a `wing`, a search path in a noun.
Note that the wing runs from left to right, ie, the opposite of
most languages: `bar.foo` means "bar within foo."
Each step in a wing is a `limb`. {Most languages use metaphors;
Hoon abuses them.} A limb can be a tree address, like `+3` or
`.`, or a label like `foo`. We can combine them in one wing:
```
~tasfyn-partyv:dojo> bar.foo.+3:test
7
```
It's important to note the difference between `bar.foo:test`
and `bar:foo:test`, even though they produce the same product:
```
~tasfyn-partyv:dojo> bar:foo:test
7
```
`bar.foo` is one twig, which we run on the product of `test`.
That's different from running `bar` on the product of `foo` on
the product of `test`.
## Mutation
Mutation? Well, not really. We can't modify nouns; the concept
doesn't even make sense in Hoon.
Rather, we build new nouns which are {logical -- the pointers are
shared, of course} copies of old ones, but with mutations. Let's
build a "mutated" copy of our test noun:
```
~tasfyn-partyv:dojo> test
[[[8 9] 5] foo=[6 bar=7]]
~tasfyn-partyv:dojo> test(foo 42)
[[[8 9] 5] foo=42]
~tasfyn-partyv:dojo> test(+8 %eight, bar.foo [%hello %world])
[[[%eight 9] 5] foo=[6 [%hello %world]]]
```
As we see, there's no need for the mutant noun to be shaped
anything like the old noun. They're different nouns.
A mutation, like `+8 %eight`, specifies a wing and a twig.
The wing, like `+8` or `bar.foo`, defines a leg to replace.
The twig runs against the original subject.
Can we use mutation to build a cyclical noun? Nice try, but no:
```
~tasfyn-partyv:dojo> test(+8 test)
[[[[[[8 9] 5] foo=[6 bar=7]] 9] 5] foo=[6 bar=7]]
```

View File

@ -1,3 +1,9 @@
---
title: Hoon 101.2: serious syntax
sort: 2
hide: true
next: false
---
# Hoon 2: serious syntax # Hoon 2: serious syntax
We've done a bunch of fun stuff on the command line. We know our We've done a bunch of fun stuff on the command line. We know our

View File

@ -1,4 +1,10 @@
# Hoon 3: our first program ---
title: Hoon 101.3: our first program
sort: 3
hide: true
next: false
---
# Hoon 101.3: our first program
It's time for us to do some actual programming. In this section, It's time for us to do some actual programming. In this section,
we'll work through that classic Urbit pons asinorum, decrement. we'll work through that classic Urbit pons asinorum, decrement.

View File

@ -1,3 +1,9 @@
---
title: Hoon 101.4: functions
sort: 4
hide: true
next: false
---
# Hoon 4: toward actual functions # Hoon 4: toward actual functions
Okay, we've programmed. We've achieved decrement. We've written Okay, we've programmed. We've achieved decrement. We've written

View File

@ -164,6 +164,19 @@ code {
padding: 0.2rem; padding: 0.2rem;
display: inline-block; display: inline-block;
} }
blockquote {
background-color: #f5f5f5;
margin: 0;
padding: 1rem;
font-style: italic;
margin-left: 3rem;
}
blockquote p {
margin: 0;
}
blockquote em {
font-style: normal;
}
ul { ul {
list-style: none; list-style: none;
padding: 0; padding: 0;

View File

@ -94,6 +94,19 @@ code
padding .2rem padding .2rem
display inline-block display inline-block
blockquote
background-color #f5f5f5
margin 0
padding 1rem
font-style italic
margin-left 3rem
blockquote p
margin 0
blockquote em
font-style normal
ul ul
list-style none list-style none
padding 0 padding 0

View File

@ -20,7 +20,7 @@ Next = React.createFactory query {
head:'r' head:'r'
meta:'j' meta:'j'
}, (recl }, (recl
displayName: "Links" displayName: "Next"
render: -> render: ->
curr = @props.kids[@props.curr] curr = @props.kids[@props.curr]
if curr?.meta?.next if curr?.meta?.next
@ -32,9 +32,11 @@ Next = React.createFactory query {
next = keys[next] next = keys[next]
next = @props.kids[next] next = @props.kids[next]
(div {className:"link-next"}, [ if next
return (div {className:"link-next"}, [
(a {href:"#{@props.path}/#{next.name}"}, "Next: #{next.meta.title}") (a {href:"#{@props.path}/#{next.name}"}, "Next: #{next.meta.title}")
]) ])
return (div {},"")
) )
module.exports = query { module.exports = query {

View File

@ -35,7 +35,6 @@ module.exports = {
}; };
},{"../dispatcher/Dispatcher.coffee":14,"../persistence/TreePersistence.coffee":20}],2:[function(require,module,exports){ },{"../dispatcher/Dispatcher.coffee":14,"../persistence/TreePersistence.coffee":20}],2:[function(require,module,exports){
var BodyComponent, CLICK, Links, TreeActions, TreeStore, a, clas, div, query, reactify, recl, ref; var BodyComponent, CLICK, Links, TreeActions, TreeStore, a, clas, div, query, reactify, recl, ref;
@ -315,7 +314,6 @@ module.exports = query({
}), div); }), div);
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./Async.coffee":3,"./BodyComponent.coffee":4,"./Reactify.coffee":11,"classnames":16}],3:[function(require,module,exports){ },{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./Async.coffee":3,"./BodyComponent.coffee":4,"./Reactify.coffee":11,"classnames":16}],3:[function(require,module,exports){
var TreeActions, TreeStore, _load, code, div, recl, ref, span; var TreeActions, TreeStore, _load, code, div, recl, ref, span;
@ -426,7 +424,6 @@ module.exports = function(queries, Child, load) {
}; };
},{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./LoadComponent.coffee":10}],4:[function(require,module,exports){ },{"../actions/TreeActions.coffee":1,"../stores/TreeStore.coffee":21,"./LoadComponent.coffee":10}],4:[function(require,module,exports){
var Logo, Next, a, clas, div, img, p, query, reactify, recl, ref; var Logo, Next, a, clas, div, img, p, query, reactify, recl, ref;
@ -469,7 +466,7 @@ Next = React.createFactory(query({
meta: 'j' meta: 'j'
} }
}, recl({ }, recl({
displayName: "Links", displayName: "Next",
render: function() { render: function() {
var curr, index, keys, next, ref1; var curr, index, keys, next, ref1;
curr = this.props.kids[this.props.curr]; curr = this.props.kids[this.props.curr];
@ -483,6 +480,7 @@ Next = React.createFactory(query({
} }
next = keys[next]; next = keys[next];
next = this.props.kids[next]; next = this.props.kids[next];
if (next) {
return div({ return div({
className: "link-next" className: "link-next"
}, [ }, [
@ -493,6 +491,8 @@ Next = React.createFactory(query({
} }
} }
} }
return div({}, "");
}
}))); })));
module.exports = query({ module.exports = query({
@ -532,7 +532,6 @@ module.exports = query({
})); }));
},{"./Async.coffee":3,"./Reactify.coffee":11,"classnames":16}],5:[function(require,module,exports){ },{"./Async.coffee":3,"./Reactify.coffee":11,"classnames":16}],5:[function(require,module,exports){
var div, recl, ref, textarea; var div, recl, ref, textarea;
@ -556,7 +555,6 @@ module.exports = recl({
}); });
},{}],6:[function(require,module,exports){ },{}],6:[function(require,module,exports){
var div, recl; var div, recl;
@ -579,7 +577,6 @@ module.exports = {
}; };
},{"./CodeMirror.coffee":5,"./EmailComponent.coffee":7,"./KidsComponent.coffee":8,"./ListComponent.coffee":9,"./SearchComponent.coffee":12,"./TocComponent.coffee":13}],7:[function(require,module,exports){ },{"./CodeMirror.coffee":5,"./EmailComponent.coffee":7,"./KidsComponent.coffee":8,"./ListComponent.coffee":9,"./SearchComponent.coffee":12,"./TocComponent.coffee":13}],7:[function(require,module,exports){
var button, div, input, p, reactify, recl, ref; var button, div, input, p, reactify, recl, ref;
@ -660,7 +657,6 @@ module.exports = recl({
}); });
},{"./Reactify.coffee":11}],8:[function(require,module,exports){ },{"./Reactify.coffee":11}],8:[function(require,module,exports){
var a, div, hr, li, query, reactify, recl, ref, ul; var a, div, hr, li, query, reactify, recl, ref, ul;
@ -732,7 +728,6 @@ module.exports = query({
})); }));
},{"./Async.coffee":3,"./Reactify.coffee":11}],9:[function(require,module,exports){ },{"./Async.coffee":3,"./Reactify.coffee":11}],9:[function(require,module,exports){
var a, clas, div, h1, li, pre, query, reactify, recl, ref, span, ul; var a, clas, div, h1, li, pre, query, reactify, recl, ref, span, ul;
@ -888,7 +883,6 @@ module.exports = query({
})); }));
},{"./Async.coffee":3,"./Reactify.coffee":11,"classnames":16}],10:[function(require,module,exports){ },{"./Async.coffee":3,"./Reactify.coffee":11,"classnames":16}],10:[function(require,module,exports){
var div, input, recl, ref, textarea; var div, input, recl, ref, textarea;
@ -929,7 +923,6 @@ module.exports = recl({
}); });
},{}],11:[function(require,module,exports){ },{}],11:[function(require,module,exports){
var Virtual, div, load, reactify, recl, ref, rele, span, walk; var Virtual, div, load, reactify, recl, ref, rele, span, walk;
@ -997,7 +990,6 @@ module.exports = _.extend(reactify, {
}); });
},{"./LoadComponent.coffee":10}],12:[function(require,module,exports){ },{"./LoadComponent.coffee":10}],12:[function(require,module,exports){
var a, div, input, query, reactify, recl, ref, var a, div, input, query, reactify, recl, ref,
slice = [].slice; slice = [].slice;
@ -1136,7 +1128,6 @@ module.exports = query({
})); }));
},{"./Async.coffee":3,"./Reactify.coffee":11}],13:[function(require,module,exports){ },{"./Async.coffee":3,"./Reactify.coffee":11}],13:[function(require,module,exports){
var div, query, reactify, recl, var div, query, reactify, recl,
slice = [].slice; slice = [].slice;
@ -1265,7 +1256,6 @@ module.exports = query({
})); }));
},{"./Async.coffee":3,"./Reactify.coffee":11}],14:[function(require,module,exports){ },{"./Async.coffee":3,"./Reactify.coffee":11}],14:[function(require,module,exports){
var Dispatcher; var Dispatcher;
@ -1287,7 +1277,6 @@ module.exports = _.extend(new Dispatcher(), {
}); });
},{"flux":17}],15:[function(require,module,exports){ },{"flux":17}],15:[function(require,module,exports){
var rend; var rend;
@ -1461,7 +1450,6 @@ $(function() {
}); });
},{"./actions/TreeActions.coffee":1,"./components/AnchorComponent.coffee":2,"./components/BodyComponent.coffee":4,"./components/Components.coffee":6,"./persistence/TreePersistence.coffee":20}],16:[function(require,module,exports){ },{"./actions/TreeActions.coffee":1,"./components/AnchorComponent.coffee":2,"./components/BodyComponent.coffee":4,"./components/Components.coffee":6,"./persistence/TreePersistence.coffee":20}],16:[function(require,module,exports){
/*! /*!
Copyright (c) 2015 Jed Watson. Copyright (c) 2015 Jed Watson.
@ -1889,7 +1877,6 @@ module.exports = {
}; };
},{}],21:[function(require,module,exports){ },{}],21:[function(require,module,exports){
var EventEmitter, MessageDispatcher, QUERIES, TreeStore, _curr, _data, _tree, clog; var EventEmitter, MessageDispatcher, QUERIES, TreeStore, _curr, _data, _tree, clog;
@ -2115,7 +2102,6 @@ TreeStore.dispatchToken = MessageDispatcher.register(function(payload) {
module.exports = TreeStore; module.exports = TreeStore;
},{"../dispatcher/Dispatcher.coffee":14,"events":22}],22:[function(require,module,exports){ },{"../dispatcher/Dispatcher.coffee":14,"events":22}],22:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors. // Copyright Joyent, Inc. and other Node contributors.
// //