on c19bc7a help sign in
urbit.org/docs/reference/advanced.udon
201 lines 8.1 kB history raw
1:- :~ navhome/'/docs/'
2 navuptwo/'true'
3 sort/'5'
4 title/'Advanced Types'
5 ==
6;>
8# Advanced types
10The definition of `type` in the 'Basic Types' section is only a simplified version. The Hoon type system is simple, but not *that* simple.
12The good news is that you can *skip this section*, at least when
13you're first learning Hoon. Polymorphism and aliasing are mainly
14for advanced programmers writing complex infrastructure and/or
15large functions. Don't worry about them for a little while.
17## The Full Version of `$type`
19```
20+$ type $~ %noun
21 $@ $? %noun
22 %void
23 ==
24 $% [$atom p=term q=(unit @)]
25 [$cell p=type q=type]
26 [$core p=type q=coil]
27 [$face p=$@(term tune) q=type]
28 [$fork p=(set type)]
29 [$hint p=(pair type note) q=type]
30 [$hold p=type q=hoon]
31 ==
32::
33+$ coil $: p=[p=(unit term) q=poly r=vair]
34 q=type
35 r=[p=seminoun q=(map term tome)]
36::
37+$ poly ?(%wet %dry)
38+$ vair ?($gold $iron $lead $zinc)
39+$ tome (pair what (map term hoon))
40+$ tune
41 $~ [~ ~]
42 $: p=(map term (unit hoon))
43 q=(list hoon)
44 ==
45```
47If you compare this to the basic `type`, you'll see that we've
48changed two parts: `%core` and `%face`. We added polymorphism to
49`%core`, and aliases and bridges to `%face`.
51(We also added `%hint` for hint expressions.)
53## `%core`: advanced polymorphism
55If cores never changed, we wouldn't need polymorphism. Of
56course, nouns are immutable and never change, but we use them as
57templates to construct new nouns around.
59Suppose we take a core, a cell `[battery payload]`, and replace
60the payload with a different noun. Then, we invoke an arm from
61the battery.
63Is this legal? Does it make sense? Every function call in Hoon
64does this, so we'd better make it work well.
66The full core stores both payload types. The type that describes
67the payload currently in the core is `p`. The type that describes
68the payload the core was compiled with is `q.q`.
70In the Bertrand Meyer tradition of type theory, there are two
71forms of polymorphism: variance and genericity. In Hoon this
72choice is per core, hence the `poly` label in `coil`: it can be either `%wet` or `%dry`. Dry polymorphism relies on variance; wet
73polymorphism relies on genericity.
75### Dry arms
77For a dry arm, we apply the Liskov substitution principle: we
78ask, "can we use any `p` as if it was a `q.q`?" This is the same
79test as in `^-` ("kethep") or any type comparison (`nest`). Intuitively,
80we ask: "is the new payload compatible with the old payload?"
82For a core `a`, if `p.a` fits in `q.q.a`, we can use arms on the
83core. The product of a dry arm whose expression is `b` is always
84defined as `[%hold a(p q.q.a, r.p.q %gold) b]`.
86In other words, the subject of the arm computation is the
87original core type. The type of the modified payload, `p`, is
88thrown away. This is of course the normal behavior of a function
89call in most languages.
91### Dry polymorphism and core nesting rules
93Dry polymorphism works by substituting cores. Typically, the
94the programmer uses one core as an interface definition, then
95replaces it with another core which does something useful.
97For core `b` to nest within core `a`, the batteries of `a` and
98`b` must have the same tree shape, and the product of each `b`
99arm must nest within the product of the `a` arm. Wet arms (see
100below) are not compatible unless the hoon is exactly the same.
102But we also apply a payload test that depends on the rules of
103variance. Again, this is traditional Meyer type theory; don't
104worry if you don't know it. These rules should make sense if you
105just think about them intuitively.
107Each core has a "metal" `r.p.q` which defines its variance model.
108A core can be *invariant* (`%gold`), *bivariant* (`%lead`),
109*covariant* (`%zinc`), or *contravariant* (`%iron`). The default
110is gold; a gold core can be cast or converted to any metal, and
111any metal can be cast or converted to lead.
113A gold core `a` has a read-write payload; another core `b` that
114nests within it (i.e., can be substituted for it) must be a gold
115core whose payload is mutually compatible (`+3.a` nests in `+3.b`,
116`+3.b` nests in `+3.a`). Hence, *invariant*.
118A lead core `a` has an opaque payload. There is no constraint on
119the payload of a core `b` which nests within it. Hence,
120*bivariant*.
122An iron core `a` has a write-only sample (payload head, `+6.a`)
123and an opaque context (payload tail, `+7.a`). A core `b` which
124nests within it must be a gold or iron core, such that `+6.a`
125nests within `+6.b`. Hence, *contravariant*.
127A zinc core `a` has a read-only sample (payload head, `+6.a`)
128and an opaque context (payload tail, `+7.a`). A core `b` which
129nests within it must be a gold or zinc core, such that `+6.b`
130nests within `+6.a`. Hence, *covariant*.
132### Wet arms
134For a wet arm, we ask: "suppose this core was actually compiled
135using `p` instead of `q.q`?" Would the Nock formula we generated
136for `q.q` actually work for a `p` payload?
138A wet arm with hoon `b` in core `a` produces the type `[%hold a
139b]`. Assuming `a` has a modified payload, this will (lazily)
140analyze the arm with the caller's modified payload, `p`.
142But of course, we don't actually recompile the arm at runtime.
143We actually run the formula generated for the original payload,
144`q.q`.
146When we call a wet arm, we're essentially using the hoon as a
147macro. We are not generating new code for every call site; we
148are creating a new type analysis path, which works as if we
149expanded the callee with the caller's context.
151Consider a function like `turn` (Haskell `map`) which transforms
152each element of a list. To use `turn`, we install a list and a
153transformation function in a generic core. The type of the list
154we produce depends on the type of the list and the type of the
155transformation function. But the Nock formulas for transforming
156each element of the list will work on any function and any list,
157so long as the function's argument is the list item.
159Again, will this work? A simple (and not quite right) way to ask
160this question is to compile all the hoons in the battery for both
161a payload of `p` and a payload of `q.q`, and see if they generate
162exactly the same Nock. The actual algorithm is a little more
163interesting, but not much.
165A Haskeller might say that in a sense, `q.q` and `q.r.q` (the
166original payload and the battery) define a sort of implicit
167typeclass. And indeed, Hoon uses wet arms for the same kinds of
168problems as Haskell typeclasses.
170Like typeclasses, wet arms / gates are a powerful tool. Don't
171use them unless you know what you're doing.
173### Constant folding
175There's only one field of the `coil` we haven't explained yet:
176`p.r.q`. This is simply the compiled battery, if available. (Of
177course, we compile the hoons in a core against the core itself,
178and the formulas can't be available while we're compiling them.)
179External users of the core want this battery constant, though: it
180lets us fold constants by executing arms at compile time.
182## `%face`: aliases and bridges
184In the advanced `tune` form, the `%face` type also has a couple
185of secret superpowers for hacking the namespace. Remember that
186Hoon doesn't have anything like a symbol table; to resolve a
187limb, we just search the type depth-first.
189If a name is in the `p.p` map, it's an alias. (An alias is defined using the
190`=*` rune.) The map contains a `(unit hoon)`; if the unit is full, the name
191resolves to that hoon (compiled against the `q` type). If the unit is empty,
192the name is blocked / skipped (see [limb](../rune/limb/) for what
193this means).
195If a name is in the `q.p` map, it's a bridge. (A bridge is defined using the
196`=,` rune.) When we search for a name, we also compile the bridge, and check
197if the name resolves against the bridge product. If so, we use it.
199These hacks let us deal with interesting large-scale problems,
200like complex library dependencies. You definitely don't need to
201understand them to just write simple Hoon programs.