These runes modify the subject. (Or more precisely, they evaluate at least one of their subexpressions with a modified subject.)
Hoon doesn't have variables in the ordinary sense. If you want to bind a name
to a value, e.g.,
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
Of course there are many variations on ways to modify the subject, useful for
different situations. Hence the whole family of
[%tsgr p=hoon q=hoon]: compose two expressions.
the product of
q, with the product of
p taken as the subject.
> =>([a=1 b=2 c=3] b) 2 > =>((add 2 4) [. .]) [6 6]
[%tsbr p=spec q=hoon]: combine a default type value with the subject.
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.
~zod:dojo> =foo |= a=@ =| b=@ =- :(add a b c) c=2 ~zod:dojo> (foo 5) 7
[%tscl p=(list (pair wing hoon)) q=hoon]: change multiple legs in the subject.
=>(%_(. p) q)
Regular: jogging, then 1-fixed.
This rune is like
=., but for modifying the values of multiple legs of the subject.
~zod:dojo> =+ a=[b=1 c=2] =: c.a 4 b.a 3 == a [b=3 c=4]
[%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.
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]
[%tsdt p=wing q=hoon r=hoon]: change one leg in the subject.
=>(%_(. p q) r)
=. 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
> =+ 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
[%tshp p=hoon q=hoon]: combine a new noun with the subject, inverted.
=>([q .] p)
=- 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.
~zod:dojo> =foo |= a=@ =+ b=1 =- (add a b c) c=2 ~zod:dojo> (foo 5) 8
[%tskt p=skin q=wing r=hoon s=hoon]: pin the head of a pair; change
a leg with the tail.
=/(p -.r =.(q +.r s))
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
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,
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,
This may also remind you of Haskell's State monad.
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]
[%tsgl p=hoon q=hoon]: compose two expressions, inverted.
=< is just
~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]
[%tsls p=hoon q=hoon]: combine a new noun with the subject.
=>([p .] q)
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.
=+ is the simplest way of "declaring a variable."
[%tssm p=skin q=hoon r=hoon]: combine a named noun with the subject, possibly with type annotation; inverted order.
=/(p r q)
=; is exactly like
=/ except that the order of its last two subexpressions is reversed.
~zod:dojo> =foo |= a=@ =/ b 1 =; c=@ :(add a b c) 2 ~zod:dojo> (foo 5) 8
[%tsfs p=skin q=hoon r=hoon]: combine a named noun with the subject, possibly with type annotation.
p is a name, (e.g.
=+(^=(p q) r)
p is a name with a type (e.g.,
=+(^-(p q) r)
?@ p =+ p=q r =+ ^-($=(p.p q.p) q) r
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."
~zod:dojo> =foo |= a=@ =/ b 1 =/ c=@ 2 :(add a b c) ~zod:dojo> (foo 5) 8
[%tssg p=(list hoon)]: compose many expressions.
The product of the chain composition.
~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
[%tstr p=term q=hoon r=hoon]: define an alias.
r, compiled with a subject in which
p is aliased to
The difference between aliasing and pinning is that pinning changes the subject, but for aliasing the subject noun stays the same. The aliased expression,
q, is recorded in the type information of
q is calculated every time you use the
~zod:dojo> =+ a=1 =* b a [a b] [1 1] ~zod:dojo> =+ a=1 =* b a =. a 2 [a b] [2 2]
[$tswt p=wing q=hoon r=hoon s=hoon]: conditionally change one leg in the subject.
=. p ?:(q r p) s
=? to replace the value of leg
r on condition
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
> =a 12 > =?(a =(1 1) 22 a) 22 > =?(a =(1 2) 22 a) 12