A core is a cell of [battery payload]
. The battery is made of one or more
arms, each of which is a computation on its parent core.
Arm runes are used to define arms in a core, and thus can only be used from within an expression that produces a multi-arm core. That means arm runes cannot be used to mark the beginning of a first-class expression -- there is no such thing in Hoon as an arm without a core.
There are various arm runes you can use to produce different kinds of arms.
Normal arms use ++
; arms defining a structure (or 'mold') use +$
; and
constructor arms use +*
.
+|
"lusbar"
Chapter label (not useful)
Syntax
One argument, fixed.
Form | Syntax |
---|---|
Tall |
+| %label |
Wide | None. |
Irregular | None. |
Discussion
The +|
doesn't produce an arm. It instead provides a label for the arms that
follow it. The arms of a core can be divided into chapters for
'organization'. Chapter labels aren't part of the underlying noun of the core;
they're stored as type system metadata only.
See tome
in the Hoon standard library.
Note: The +|
rune has little practical utility. Chapter labels cannot be
referenced short of manually processing the $type
of a core.
Examples
Let's look at what the Hoon compiler's parser, ream
, does with the +|
rune:
> (ream '|% +| %numbers ++ two 2 ++ three 3 --')
[ %brcn
p=~
q
{ [ p=%numbers
q=[p=~ q={[p=%three q=[%sand p=%ud q=3]] [p=%two q=[%sand p=%ud q=2]]}]
]
}
]
Notice that p.q
has the label %numbers
. Contrast with:
> (ream '|% ++ two 2 ++ three 3 --')
[ %brcn
p=~
q
{ [ p=%$
q=[p=~ q={[p=%three q=[%sand p=%ud q=3]] [p=%two q=[%sand p=%ud q=2]]}]
]
}
]
+$
"lusbuc"
Produce a structure arm (type definition).
Syntax
Two arguments, fixed.
Form | Syntax |
---|---|
Tall |
+$ p=term q=spec |
Wide | None. |
Irregular | None. |
p
is an arm name, and q
is any structure expression.
Discussion
Arms produced by +$
are essentially type definitions. They should be used when one wants to define custom types using core arms.
The Hoon subexpression, q
, must be a structure expression. That is, it must be
either a basic structure expression (*
, ~
, ^
, ?
, and @
), or a complex
expression made with the $
family of runes (including irregular variants).
Names of structures are also permitted (e.g., tape
).
Examples
> =c |%
+$ atom-pair $:(@ @)
+$ flag-atom $:(? @)
--
> `atom-pair.c`[12 14]
[12 14]
> `atom-pair.c`[12 [22 33]]
nest-fail
> `flag-atom.c`[& 22]
[%.y 22]
++
"luslus"
Produce a normal arm.
Syntax
Two arguments, fixed.
Form | Syntax |
---|---|
Tall |
++ p=term q=hoon |
Wide | None. |
Irregular | None. |
p
is the arm name, and q
is any Hoon expression.
Discussion
All arms must have a name (e.g., add
). An arm is computed by name resolution.
(This resolution is implicit in the case of $
arms. See |=
, |-
, and |^
.)
The ++
rune is used for explicitly giving a name to an arm.
Any Hoon expression, q
, may be used to define the arm computation.
Examples
> =c |%
++ two 2
++ increment |=(a=@ +(a))
--
> two.c
2
> (increment.c 11)
12
+*
"lustar"
Defines deferred expressions within doors.
Syntax
Arguments: A variable number of pairs.
Form | Syntax |
---|---|
Tall |
+* a=term b=hoon c=term d=hoon ... e=term f=hoon |
Wide | None. |
Irregular | None. |
a
, c
, e
are arm names and b
, d
, f
are any Hoon expression. Note that
unlike all other runes with a variable number of arguments, the list of
arguments of +*
does not end with a terminator.
+*
arms must always come at the beginning of the battery, before any other
type of lus arm.
Discussion
The primary use of +*
is to create deferred expressions within doors (see
Examples below). This is a name for an expressions that will be evaluated in
each place the name is dereferenced. This is a similar concept to aliases or
macros, but there are some subtle but important differences. Deferred
expressions given by +*
do not count towards the number of arms in the door
and thus are also called "virtual arms", which can be important for things like
Gall agent cores that require a fixed number of arms.
Under the hood, +*
gets compiled as
=*
's (see here for more discussion on
deferred expressions). +* foo bar
rewrites each ++
arm beneath it in the
core to include =* foo bar
. For example, the interpreter sees the Nock
compiled from this Hoon expression
|_ z=@ud
+* n 1
++ x (add z n)
++ y (sub z n)
--
as being identical the Nock compiled from this one:
=| z=@ud
|%
++ x
=* n 1
(add z n)
++ y
=* n 1
(sub z n)
--
Examples
To assign an alias to a door, we often write the following.
|_ foo
+* this .
This is the idomatic way to assign the alias this
to the door.
Sometimes cores, such as Gall app cores, have a fixed number of arms, but you'd
like to include more. This is where aliases employed as "virtual arms" may be of
use. We note that it is often better style to compose cores with =>
or =<
to add more arms to a
Gall app core. This usage of +*
is controversial and should be minimized.
|_ =bowl:gall
+* this .
samp +<
cont +>
This assigns the door the alias this
, the sample of the door samp
, and the
context of the door cont
.
You may also call functions with +*
by making use of e.g. the %~
rune.
=<
|_ a=@
+* do ~(. +> a)
++ stuff foo:do
::etc
--
|_ b=@
++ foo %bar
::etc
--