Lesson 7: The Standard Library

recordings:

Lesson 7 (US Morning) YouTube | FileBase

Lesson 7 (US Evening) YouTube | FileBase

objectives:

runes:

irregular:

keypoints:

homework:

The Standard Library

Whenever we run code in the dojo, the subject makes available to us a standard library of operations. Much of these focus on parsing and building code—after all, that's what Hoon itself must do—but there are many other convenient functions tucked away in the Hoon subject. Some parts are formally in Arvo, some in %zuse, some in %lull, and some in Hoon proper (hoon.hoon). (Vane-specific operations are also available, although we don't need any of them quite yet.) You don't really need to know about where particular parts live yet, although naked generators as we've composed thus far can only see arms of the standard library and don't have access to some Arvo information like our or now.

The Structure of Urbit OS

Navigate to /sys in your fakezod's pier in the %base desk. Take a look at the files present here:

. ├── arvo.hoon ├── hoon.hoon ├── lull.hoon ├── vane │   ├── ames.hoon │   ├── behn.hoon │   ├── clay.hoon │   ├── dill.hoon │   ├── eyre.hoon │   ├── gall.hoon │   ├── iris.hoon │   └── jael.hoon └── zuse.hoon

Arvo and the vanes provide system services which you won't need until you start working with Gall and building apps.

We are going to venture into the standard library files to start us off today. Open these with the text editor of your choice. Let's start with hoon.hoon, the core of the standard library.

hoon.hoon

hoon.hoon is a bit of a jungle. It is a core organized into “chapters” with +| lusbarThe docs reflect this structure and give us a good glimpse of what to expect in here. Some highlights:

Let's examine some specific implementations:

How do we convert text into all upper-case?

How do we turn a cord into a tape?

How can we make a list of a null-terminated tuple?

How can we evaluate Nock expressions?

(If you see a |* bartar rune in there, it's similar to a |= bartis, but what's called a wet gate.)

zuse.hoon

When you open zuse.hoon, you'll see that it is composed with some data structures from %lull, but that by and large it consists of a core including arms organized into “engines”.

Most of these are internal Arvo conventions, such as conversion between Unix-epoch times and Urbit-epoch times. The main one you are likely to work with is the ++html core, which contains important tools for working with web-based data, such as MIME types and JSON strings.

To convert a @ux hexadecimal value to a cord:

(en:base16:mimes:html [3 0x12.3456]) '123456'

To convert a cord to a @ux hexadecimal value:

@uxq.+>:(de:base16:mimes:html '123456') 0x12.3456

There are tools for working with Bitcoin wallet base-58 values, JSON strings, XML strings, and more.

(en-urlt:html "https://hello.me") "https%3A%2F%2Fhello.me"

What seems to be missing from the standard library?

Conditional Expressions

Let's wrap up the ? wut runes, many of which you have already seen:

Conditional decision-making:

Assertions:

Logical operators:

Pattern matching:

Functional Programming

Given a gate, you can manipulate it to accept a different number of values than its sample formally requires, or otherwise modify its behavior.

Changing Arity

If a gate accepts only two values in its sample, for instance, you can chain together multiple calls automatically using ;: miccol:

(add 3 (add 4 5)) 12 :(add 3 4 5) 12 (mul 3 (mul 4 5)) 60 :(mul 3 4 5) 60

This is called changing the arity of the gate. (Does this work on ++mul:rs?)

Binding the Sample

If you have a gate which accepts multiple values in the sample, you can fix one of these. To fix the head of the sample (the first argument), use ++cury; to bind the tail, use ++curr.

Consider calculating a x² + b x + c, a situation we earlier resolved using a door. We can resolve the situation differently using currying:

=full |=([x=@ud a=@ud b=@ud c=@ud] (add (add (mul (mul x x) a) (mul x b)) c)) (full 5 4 3 2) 117 =one (curr full [4 3 2]) (one 5) 117

One can also ++cork a gate, or arrange it such that it applies to the result of the next gate. This pairs well with ;: miccol. (There is also ++corl.) This example converts a value to @ux then decrements it:

((cork dec @ux) 20) 0x13

Reeling A Jig

++roll and ++reel are used to left-fold and right-fold a list, respectively. To fold a list is similar to ++turn, except that instead of yielding a list with the values having had each applied, ++roll and ++reel produce an accumulated value.

(roll (list @)[1 2 3 4 5 ~] add) q=15 (reel (list @)[1 2 3 4 5 ~] mul) 120

Formatted Text

A +$tank is a formatted print tree. Error messages and the like are built of tanks. They are defined in hoon.hoon:

:: tank @ cord tang (list tank) :: bottom-first error

The ++ram:re arm is used to convert these to actual formatted output, e.g.

~(ram re leaf+"foo") "foo" ~(ram re [%palm ["|" "(" "!" ")"] leaf+"foo" leaf+"bar" leaf+"baz" ~]) "(!foo|bar|baz)" ~(ram re [%rose [" " "[" "]"] leaf+"foo" leaf+"bar" leaf+"baz" ~]) "[foo bar baz]"

Many generators build sophisticated output using tanks and the short-format builder +, e.g. in /gen/azimuth-block/hoon:

[leaf+(scow %ud block)]~

At this point we aren't going to use tanks directly yet, but you'll see them more and more as you move into more advanced generators.

Deep Dive: cat.hoon

For instance, how does +cat work? Let's look at the structure of /gen/cat/hoon:

:: ConCATenate file listings :: :::: /hoon/cat/gen :: /? 310 /+ pretty-file, show-dir :: :::: :: :- %say |= [^ [arg=(list path)] vane=?(%g %c)] =- tang+(flop tang(zing -)) %+ turn arg |= pax=path ^- tang =+ ark=.^(arch (cat 3 vane %y) pax) ?^ fil.ark ?: =(%sched -:(flop pax)) [>.^((map @da cord) (cat 3 vane %x) pax)<]~ [leaf+(spud pax) (pretty-file .^(noun (cat 3 vane %x) pax))] ?- dir.ark :: handle ambiguity ~ [rose+[" " ~]^~[leaf+"~" (smyt pax)]]~ :: [[@t ~] ~ ~] $(pax (welp pax /[p.n.dir.ark])) :: * =- [palm+[": " ``~]^-]~ :~ rose+[" " ]^[leaf+"*" (smyt pax)] tank(show-dir vane pax dir.ark) == ==