--- title: Hoon 101.4: functions sort: 4 hide: true next: false --- # Hoon 4: toward actual functions Okay, we've programmed. We've achieved decrement. We've written what is in some sense a loop. What next? Well... we're still feeling vaguely disappointed. Because we're supposed to be doing *functional programming*. And we haven't yet written any *functions*. After all, in Hoon we don't really write a command-line utility to decrement `42`. We write `(dec 42)`. You probably realize that on the inside, this is not the same thing as a function in a normal functional language. The Tasmanian tiger is not a tiger. On the other hand, it certainly *looks* like a function call. So how do we write the function? In this chapter, we'll modify `+test` to extend the subject so that we can write our result as `(dec arg)`. Or rather, `(duck arg)`, because we want to get out of training wheels and stop clearing the subject soon. ## Form of the solution ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun (duck arg) !! :: some interesting core ``` `!!`, or "zapzap" or `[%zpzp ~]`, can go anywhere a twig can and always crashes. Because its span is the empty set (`%void`), it doesn't cause type inference problems. In place of the `!!`, we'll put a core, effectively a library, that provides our new, improved decrement function `duck`. We'll then call it with the irregular form, `(duck arg)`, which looks like a function call but is in fact some mysterious macro. ## Some interesting core Translated into imperative programming, what we did in chapter 3 was more like computing a function of a global variable. Now, we have to actually pass an argument to a function. Here's our first try: ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun =+ gat=duck =<(run gat(sam arg)) => ~ |% ++ duck =+ sam=0 =+ pre=0 |% ++ run ?: =(sam +(pre)) pre run(pre +(pre)) -- -- ~tasfyn-partyv:dojo/sandbox> +test 42 41 ``` We step back and contemplate our handiwork. Is it good? Well... it works. Reading programs written without syntactic sugar is about as fun as eating raw chocolate nibs. What did we do? In the `duck` arm (we often write `++duck`, for obvious reasons) we produce a core whose payload is `[pre=0 num=0 ~]`, and whose battery contains `++run`. In the result twig, we first use `++duck` to extend our subject with a core named `gat`. We then use `run` on that gate. Why do we need this `gat`? Why can't we just write `=<(run duck(sam arg))`? Because the arm is computed *after* the mutation. But here we need the mutated *result* of `++duck`. Instead, what this code is doing is trying to mutate `sam` within the core that contains `++duck`. Where it doesn't exist, so your code won't compile. And note that with `=<`, we've placed our library structurally between the original subject and the program we're writing, but lexically at the bottom with zero left margin. We also clear the subject to keep things simple. ## A more regular structure It actually gets worse. To make this code look simpler, we need to make it more complex. While "function calls" actually fit quite well into the Hoon architecture, they're also a nontrivial synthetic construction. We'll build the desugared form the hard way, then show you where we put the sugar in. The desugared canonical decrement: ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun =+ gat=duck =<(run gat(sam arg)) => ~ |% ++ duck =+ sam=0 |% ++ run =+ pre=0 =< loop |% ++ loop ?: =(sam +(pre)) pre loop(pre +(pre)) -- -- -- ~tasfyn-partyv:dojo/sandbox> +test 42 41 ``` Yuck. Okay, let's fix this. ## Art of the loop First, look at our little `++loop`. It works just like our old `++run` loop. We notice that there's actually something nice about it: we don't use the symbol `loop` anywhere outside these 7 lines of code. It's not exported at all. Actually, the symbol `loop` name is useless and redundant. Making up names is one of the hard problems in computer science, so why solve it? For just this reason, Hoon has an *empty name*, which as a constant is a zero-length symbol (`%$` instead of `%foo`), and as a limb is the `buc` symbol (`$`). With `$`, our loop becomes: ``` =< $ |% ++ $ ?: =(sam +(pre)) pre $(sam +(run)) -- ``` This may not seem like a huge improvement. It's not. But it's exactly equivalent to the synthetic rune `|-`, "bardas": ``` |- ?: =(sam +(pre)) pre $(pre +(pre)) ``` This is obviously the canonical Hoon loop. It leaves us with ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun =+ gat=duck =<(run gat(sam arg)) => ~ |% ++ duck =+ sam=0 |% ++ run =+ pre=0 |- ?: =(sam +(pre)) pre $(pre +(pre)) -- -- ~tasfyn-partyv:dojo/sandbox> +test 42 41 ``` ## Is this a lambda? Could we use `$` for `++run`? It certainly sounds like the same kind of thing as `++loop` -- just a word we invented to mean "do it." Should the programmer have to invent these kinds of words? ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun =+ gat=duck =<($ gat(sam arg)) => ~ |% ++ duck =| sam=@ud |% =+ pre=0 ++ $ |- ?: =(sam +(pre)) pre $(pre +(pre)) -- -- ~tasfyn-partyv:dojo/sandbox> +test 42 41 ``` (Besides `run` to `$`, we changed `=+ sam=0` to `=| sam=@ud`. Let's just remember that there's some magic here. We'll come back and explain it later.) This is still kind of ugly -- but it's exactly equivalent to ``` =< :- %say |= [* [[arg=@ud ~] ~]] :- %noun =+ gat=duck =<($ gat(sam arg)) => ~ |% ++ duck |= sam=@ud =+ pre=0 |- ?: =(sam +(pre)) pre $(pre +(pre)) -- ~tasfyn-partyv:dojo/sandbox> +test 42 41 ``` Doesn't that look like a function? Indeed, we're done with `++duck` -- that's what a Hoon decrement should look like. If you squint a little, `|=` ("bartis") might even be a strange, deformed lambda rune. Since it's doing something simple, we might well even compress the whole body of the function into one wide-form line: ``` =+(pre=0 |-(?:(=(sam +(pre)) pre $(pre +(pre))))) ``` (According, of course, to taste -- this is a bit tight for some.) ## Gates and how to call them Our call site remains a disaster, though. We'll need moar sugar. But first, let's look at this lambda-thing we've made. What is the noun produced by `++duck`? Our term for it is a "gate," but nobody will hate you for saying "function." And while we "slam" our gates, you can feel free to just "call" them. A gate is a core, of course, but a special kind of core. All cores are shaped like `[battery payload]`. A gate is shaped like `[formula [sample context]]`. A gate has one arm, `$`, so its battery is just a formula. To slam a gate, you replace its sample (`+6` or `+<`, "luslit" or "lust") with your own noun, and apply the formula to the mutated gate. As we explained earlier, `duck(sam arg)` is not the right way to mutate the gate we make with `duck`, because it's actually trying to mutate the core we used to make `duck`. But there has to be some sugar to do this, and there is: `%*`, "centar". We can replace our call site with `%*($ duck sam arg)`. This is also not quite orthodox, because the whole point of a gate is the canonical shape that defines a calling convention. We can and should say: `%*($ duck +< arg)`. Unsurprisingly, this in turn is `%-(duck arg)` in regular form, or `(duck arg)`