These runes modify the subject. (Or more precisely, they evaluate at least one of their subexpressions with a modified subject.)
Overview
Hoon doesn't have variables in the ordinary sense. If you want to bind a name
to a value, e.g., a
to 12
, you do so by pinning 12
to the subject and
associating the name with it. This sort of operation is done with the =
family of runes.
Let's say you have some old subject p
. To 'pin' a value to the head means to
modify the subject by repacing it with a cell of [new-value p]
. The head of
the cell is the new value. So to pin 12
with the face a
the new subject
would be: [a=12 p]
.
Of course there are many variations on ways to modify the subject, useful for
different situations. Hence the whole family of =
runes.
Runes
=>
"tisgar"
[%tsgr p=hoon q=hoon]
: compose two expressions.
Produces
the product of q
, with the product of p
taken as the subject.
Syntax
Regular: 2-fixed.
Examples
> =>([a=1 b=2 c=3] b)
2
> =>((add 2 4) [. .])
[6 6]
=|
"tisbar"
[%tsbr p=spec q=hoon]
: combine a default type value with the subject.
Expands to
=+(*p q)
Syntax
Regular: 2-fixed.
Discussion
The default (or 'bunt') value of p
is pinned to the head of the subject. Usually p
includes a name for ease of reference.
Speaking more loosely, =|
usually "declares a variable" which is "uninitialized," presumably because you'll set it in a loop or similar.
Examples
~zod:dojo> =foo |= a=@
=| b=@
=- :(add a b c)
c=2
~zod:dojo> (foo 5)
7
=:
"tiscol"
[%tscl p=(list (pair wing hoon)) q=hoon]
: change multiple legs in the subject.
Expands to
=>(%_(. p) q)
Syntax
Regular: jogging, then 1-fixed.
Discussion
This rune is like =.
, but for modifying the values of multiple legs of the subject.
Examples
~zod:dojo> =+ a=[b=1 c=2]
=: c.a 4
b.a 3
==
a
[b=3 c=4]
=,
"tiscom"
[%tscm p=hoon q=hoon]
: expose namespace
p
evaluates to a noun with some namespace. From within q
you may access p
's names without a wing path (i.e., you can use face b
rather than b.p
). This is especially useful for calling arms from an imported library core or for calling arms from a stdlib core repeatedly.
Syntax
Regular: 2-fixed.
Examples
With an imported core:
> (sum -7 --7)
-find.sum
[crash message]
> (sum:si -7 --7)
--0
> =, si (sum -7 --7)
--0
With a dojo-defined face:
> =/ fan [bab=2 baz=[3 qux=4]]
=, fan
[bab qux.baz]
[2 4]
=.
"tisdot"
[%tsdt p=wing q=hoon r=hoon]
: change one leg in the subject.
Expands to
=>(%_(. p q) r)
Syntax
Regular: 3-fixed.
Discussion
Technically the =.
rune doesn't change the subject. It creates
a new subject just like the old one except for a changed value at p
. Note that the mutation uses %_
("cencab"), so the type at p
doesn't change. Trying to change the value type results in a nest-fail
.
Examples
> =+ a=[b=1 c=2]
=. b.a 3
a
[b=3 c=2]
> =+ a=[b=1 c=2]
=.(b.a 3 a)
[b=3 c=2]
> =+ a=[b=1 c=2]
=.(b.a "hello" a)
nest-fail
=-
"tishep"
[%tshp p=hoon q=hoon]
: combine a new noun with the subject, inverted.
Expands to
=>([q .] p)
Syntax
Regular: 2-fixed.
Discussion
=-
is just like =+
but its subexpressions are reversed. =-
looks better than =+
when the expression you're pinning to the subject is much smaller than the expression that uses it.
Examples
~zod:dojo> =foo |= a=@
=+ b=1
=- (add a b c)
c=2
~zod:dojo> (foo 5)
8
=^
"tisket"
[%tskt p=skin q=wing r=hoon s=hoon]
: pin the head of a pair; change
a leg with the tail.
Expands to
=/(p -.r =.(q +.r s))
Syntax
Regular: 4-fixed.
Discussion
p
is a new name (possibly with type annotation, e.g., a=@
) of a value to be pinned to the subject. The value of p
is the head of the product of r
. q
is given the value of the tail of r
's product. Then s
is evaluated against this new subject.
We generally use =^
when we have a state machine with a function, r
, that
produces a cell, whose head is a result and whose tail is a new
state. The head value is given a new name p
, and the
tail is stuffed back into wherever we stored the old state, q
.
This may also remind you of Haskell's State monad.
Examples
The og
core is a stateful pseudo-random number generator.
We have to change the core state every time we generate a
random number, so we use =^
:
~zod:dojo> =+ rng=~(. og 420)
=^ r1 rng (rads:rng 100)
=^ r2 rng (rads:rng 100)
[r1 r2]
[99 46]
=<
"tisgal"
[%tsgl p=hoon q=hoon]
: compose two expressions, inverted.
Expands to
=>(q p)
Syntax
Regular: 2-fixed.
Irregular: foo:baz
is =<(foo baz)
.
Discussion
=<
is just =>
backwards.
Examples
~zod:dojo> =<(b [a=1 b=2 c=3])
2
~zod:dojo> =< b
[a=1 b=2 c=3]
2
~zod:dojo> b:[a=1 b=2 c=3]
2
~zod:dojo> [. .]:(add 2 4)
[6 6]
=+
"tislus"
[%tsls p=hoon q=hoon]
: combine a new noun with the subject.
Expands to
=>([p .] q)
Syntax
Regular: 2-fixed.
Discussion
The subject of the =+
expression, call it a
, becomes the cell [p a]
for the evaluation of q
. That is, =+
'pins a value', p
, to the head of the subject.
Loosely speaking, =+
is the simplest way of "declaring a variable."
Examples
=;
"tismic"
[%tsmc p=skin q=hoon r=hoon]
: combine a named noun with the subject, possibly with type annotation; inverted order.
Expands to
=/(p r q)
Syntax
Regular: 3-fixed.
Discussion
=;
is exactly like =/
except that the order of its last two subexpressions is reversed.
Examples
~zod:dojo> =foo |= a=@
=/ b 1
=; c=@ :(add a b c)
2
~zod:dojo> (foo 5)
8
=/
"tisfas"
[%tsfs p=skin q=hoon r=hoon]
: combine a named noun with the subject, possibly with type annotation.
Expands to
if p
is a name, (e.g. a
):
=+(^=(p q) r)
if p
is a name with a type (e.g., a=@
):
=+(^-(p q) r)
Desugaring
?@ p
=+ p=q
r
=+ ^-($=(p.p q.p) q)
r
Syntax
Regular: 3-fixed.
Discussion
p
can be either a name or a name=type. If it's just a name,
=/
("tisfas") "declares a type-inferred variable." If it has a type, =/
"declares a type-checked variable."
Examples
~zod:dojo> =foo |= a=@
=/ b 1
=/ c=@ 2
:(add a b c)
~zod:dojo> (foo 5)
8
=~
"tissig"
[%tssg p=(list hoon)]
: compose many expressions.
Produces
The product of the chain composition.
Syntax
Regular: running.
Examples
~zod:dojo> =~ [sub (mul 3 20) (add 10 20)]
(sub +)
+(.)
==
31
~zod:dojo> =foo =| n=@
=< =~ increment
increment
increment
n
==
|%
++ increment
..increment(n +(n))
--
~zod:dojo> foo
3
=*
"tistar"
[%tstr p=term q=hoon r=hoon]
: define a macro.
Produces
r
, compiled with a subject in which p
is a macro for q
.
Syntax
Regular: 3-fixed.
Discussion
The difference between macroing and pinning is that pinning changes the subject, but for macroing the subject noun stays the same. The macro'd expression, q
, is recorded in the type information of p
. q
is calculated every time you use the p
macro.
Examples
~zod:dojo>
=+ a=1
=* b a
[a b]
[1 1]
~zod:dojo>
=+ a=1
=* b a
=. a 2
[a b]
[2 2]
=?
"tiswut"
[$tswt p=wing q=hoon r=hoon s=hoon]
: conditionally change one leg in the subject.
Expands to
=. p ?:(q r p)
s
Syntax
Regular: 4-fixed.
Discussion
Use =?
to replace the value of leg p
with r
on condition q
. As
usual, we are not actually mutating the subject, just creating
a new subject with a changed value. The change in value includes a
type check against the old subject; the type of r
must nest under
the type of p
.
Examples
> =a 12
> =?(a =(1 1) 22 a)
22
> =?(a =(1 2) 22 a)
12