on dc20522 help sign in
urbit.org/tutorials/hoon/structures-and-complex-types.md
356 lines 13 kB history raw
1+++
2title = "2.3 Structures and Complex Types"
3weight = 27
4template = "doc.html"
5aliases = ["/docs/learn/hoon/hoon-tutorial/structures-and-complex-types/"]
6+++
8In this lesson we'll talk a little about how type expressions become structures, and how these structures manifest in different ways in different parts of your Hoon code. We'll also talk about how to create your own custom-defined complex types from simpler ones.
10## Structures
12Attentive readers may remember that Hoon programs are made of expressions. By definition, an expression produces a value. We've talked about expressions for types such as `@`, `^`, `[? *]`, etc. What values do these subexpressions produce? The answer is that they produce a **structure**. But what are structures, and what role do they play in Hoon?
14You don't actually need to know much about what a structure is in order to write Hoon programs that use the type system effectively. Accordingly, we'll save the particular details for a later lesson. Here we'll give only a sketch of the most important features.
16### Cast Expressions
18Structures play different roles in different code contexts. First, let's look at type expressions in casts:
20```
21> ^-(@ 15)
2215
24> ^-(^ [15 17])
25[15 17]
27> ^-([? *] [%.y [15 17]])
28[%.y [15 17]]
29```
31The `@`, `^`, and `[? *]` subexpressions have no effect on the overall value produced.
33It's important to understand that these casts don't affect the [runtime](https://en.wikipedia.org/wiki/Run_time_%28program_lifecycle_phase%29) semantics of a program at all. They affect only the compiler behavior at compile-time. The compiler does these type-checks when compiling, but the resulting code has no value corresponding to the types above.
35Accordingly, the structures produced by the type subexpressions above aren't part of the program's runtime semantics. They are compile-time values only.
37### Type Example Values ('Bunt' Values)
39In other cases, structures _can_ have an effect on runtime semantics. For example, consider the expression `|=(a=@ 15)`. This produces a gate that takes any atom as its sample and returns `15`.
41The `@` subexpression of `|=(a=@ 15)` produces a structure at compile time. In the compiled program this structure is converted to a default value for the appropriate type, sometimes called an **example** value (or a **bunt** value).
43```
44> |=(a=@ 15)
45< 1.xqz
46 { a/@
47 {our/@p now/@da eny/@uvJ}
48 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
49 }
52> a:|=(a=@ 15)
54```
56As you can see, the example value for `@` is `0`. Example values are used as placeholder data for the gate's sample. You can prepend `*` to a type expression to see the default value of that type:
58```
59> *^
60[0 0]
62> *?
63%.y
65> *@
68> *@ux
690x0
70```
72### Molds
74Structures can also become gates at runtime. To produce such a gate, use a type expression as a stand-alone expression in the dojo:
76```
77> @
78< 1.goa
79 { *
80 {our/@p now/@da eny/@uvJ}
81 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
82 }
85> ?
86< 1.zgf
87 { *
88 {our/@p now/@da eny/@uvJ}
89 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
90 }
93> ^
94< 1.ylu
95 { *
96 {our/@p now/@da eny/@uvJ}
97 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
98 }
100```
102In all three cases, the result of evaluation is a gate. For each, the head is a single arm, signified by `1.xxx`. The sample -- i.e., the head of the tail -- in each case is of the type `*`. These gates are sometimes called **molds**.
104Molds are gates with two special properties: (1) they are guaranteed to produce a value of the type indicated by the type expression, and (2) they are [idempotent](https://en.wikipedia.org/wiki/Idempotence). (A gate `i` is idempotent if and only if the result of applying `i` multiple times to a value produces the same result as applying it once. In other words, `(i val)` must produce the same result as `(i (i val))`.)
106```
107> (@ 123)
108123
110> (@ (@ 123))
111123
113> (@ 'hello')
114478.560.413.032
116> (@t 'hello')
117'hello'
119> (^ [12 14])
120[12 14]
122> (^ (^ [12 14]))
123[12 14]
125> (? %.y)
126%.y
127```
129But what if we call a mold with the 'wrong' type of sample? It will crash:
131```
132> (@ [12 14])
133ford: %ride failed to execute:
134```
136Molds are designed for data validation. We won't discuss that particular use case here.
138## Constructing Complex Types
140Up to this point we've only talked about relatively simple data types. You've seen (1) the basic types and (2) one way of combining basic types to make complex types. In the rest of this lesson you'll learn other ways to create custom data types in Hoon.
142Let's review (1) and (2) briefly.
144### Basic Types
146The basic types of Hoon are: `*` for nouns, `@` for atoms (possibly with aura information, e.g., `@ud` and `@sx`), `^` for cells, `?` for flags, and `~` for null. You can also make constant, one-value types by using `%` followed by a series of lowercase letters, the hyphen symbol `-`, and numbers. E.g., `%red`, `%2`, `%kebab-case123`. The lone values of these one-value types are sometimes called 'tags'.
148Let's illustrate with the irregular `\` \`` cast syntax:
150```
151> `%blah`%blah
152%blah
154> `%blah`%not-blah
155nest-fail
156```
158### Complex Types
160In certain parts of Hoon code (not all) you can define a complex cell type from simpler types using square brackets, `[ ]`. For some examples: `[@ ^]`, `[@ud @ub]`, `[@t [? ^]]`, `[%employee @t ? @]` etc.
162```
163> `[@ud @ub]`[12 0b11]
164[12 0b11]
166> `[@ud @ub]`[12 14]
167nest-fail
169> `[%employee @t ? @]`[%employee 'Bob Smith' %.y 123]
170[%employee 'Bob Smith' %.y 123]
172> `[%employee @t ? @]`[%employer 'John Williams' %.n 321]
173nest-fail
174```
176## Building Structures: The `$` Rune Family
178The purpose of the `$` family of runes is to construct user-defined complex structures from simpler ones. Let's take a look at some of these runes and use them to make custom types.
180### `$:` Build a Cell Structure
182The `$:` takes two subexpressions, each of which must be a structure. The result is a cell structure whose head and tail are the two structures indicated. For example, the type defined by `$:(@ ?)` is the set of cells whose head is an atom, `@` and whose tail is a flag, `?`. Most of the time you can achieve the same result using square brackets: `[@ ?]`. (Most of the time, but not always!)
184```
185> `$:(@ ?)`[123 %.y]
186[123 %.y]
188> `$:(@ ?)`[%.y 123]
189nest-fail
191> `$:(%yes ?)`[%yes %.n]
192[%yes %.n]
194> `$:(%yes ?)`[%no %.n]
195nest-fail
196```
198#### Two Interpretations for `[@ ?]` (and Other Such Expressions)
200Why are `$:(@ ?)` and `[@ ?]` the same only 'most of the time'? Why not always? The answer has to do with the way Hoon handles certain rune subexpressions. Some subexpressions are reserved exclusively for types. For example, the `^-` rune is always followed by two subexpressions, the first of which must indicate a type. Subexpressions reserved exclusively for types are interpreted as types. These subexpressions must **always** produce a single structure, at least as an intermediate piece of data at compile-time. When `[@ ?]` is interpreted by Hoon as indicating a type, the result is a structure equivalent to that of `$:(@ ?)`.
202The first subexpression after the `|=` rune is also interpreted in the same way, i.e., as giving a type definition (in this case for the gate sample).
204But expressions of Hoon that aren't exclusively for types interpret expressions such as `[@ ?]` differently, i.e., as a cell of structures. Interpreted in this way, `[@ ?]` isn't equivalent to `$:(@ ?)`.
206`$:` expressions _always_ evaluate to a single structure, regardless of where they're located in the code. Expressions like `[@ ?]` are only understood as a single structure if it's a subexpression that must indicate a type; otherwise it's taken to be a pair of structures.
208Here we can see the difference by noting how many molds each produces:
210```
211> $:(@ ?)
212< 1.igg
213 { *
214 {our/@p now/@da eny/@uvJ}
215 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
216 }
219> [@ ?]
220[ < 1.goa
221 { *
222 {our/@p now/@da eny/@uvJ}
223 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
224 }
225 >
226 < 1.zgf
227 { *
228 {our/@p now/@da eny/@uvJ}
229 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
230 }
231 >
233```
235You can force `[@ ?]` to be interpreted as a single mold by prepending it with `,`: `,[@ ?]`. However, there usually is no need for this.
237```
238> ,[@ ?]
239< 1.igg
240 { *
241 {our/@p now/@da eny/@uvJ}
242 <19.arv 24.fmf 7.mpi 38.ard 119.spd 241.plj 51.zox 93.pqh 74.dbd 1.qct $141>
243 }
245```
247### `$-` Define a Gate Type
249You can use `$-` to define a gate type. The `$-` rune takes two subexpressions, which correspond to the gate input type and output type, respectively. For example, if you want to cast for a gate that takes `@` and returns `@` when called, use `$-(@ @)`:
251```
252> (`$-(@ @)`|=(@ `@`15) 12)
25315
255> (`$-(@ @)`|=(@ `*`15) 12)
256nest-fail
258> `$-(@ @)`add
259nest-fail
261> `$-([@ @] @)`add
262<1|efh {{@ @} {@ @} @}>
264> `$-([@ @] ?)`gte
265<1|efh {{@ @} {@ @} ?($.n $.y)}>
266```
268### `$?` Define a Union
270In set theory, the [union](https://en.wikipedia.org/wiki/Union_%28set_theory%29) of sets A and B is a set containing all members of both A and B. For example, the union of the set of even integers and the set of odd integers is the set of all integers.
272It's useful to be able to define a type that is the union of other types. The `$?` rune lets us do this. The `$?` takes a series of subexpressions, each of which must be a structure. The resulting type is the union of all types indicated in the expression. For example, `$?(%green %yellow %red)` is the union of the types indicated by `%green`, `%yellow`, and `%red`.
274```
275> `$?(%green %yellow %red)`%green
276%green
278> `$?(%green %yellow %red)`%yellow
279%yellow
281> `$?(%green %yellow %red)`%red
282%red
284> `$?(%green %yellow %red)`%blue
285nest-fail
286```
288The irregular form of `$?` is just `?( )`:
290```
291> `?(%green %yellow %red)`%green
292%green
294> `?(%green %yellow %red)`%yellow
295%yellow
296```
298`$?` should only be used on types that are disjoint, i.e., which have no values in common. For example, it shouldn't be used on atom types differing only in aura.
300```
301> `?(@ud @ux)`10
30210
304> `?(@ud @ux)`0x12
30518
306```
308Notice that in the latter cast, the type of the literal `0x12` is ignored and the value is printed as `@ud`. To avoid this when using `$?`, make sure you use types with no values in common.
310### `$%` Define a Tagged Union
312A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) is a structure corresponding to a union of tagged cell types. A tagged cell is a cell whose head is a tag, e.g., `[%employee name='John Smith' full-time=%.y]`. The type of this cell is `[%employee name=@t full-time=?]`, and you may want a union of this type and another tagged cell type, `[%customer name=@t]`. To construct such a type, use `$%`.
314The `$%` rune takes a series of subexpressions, each of which must define a tagged cell type. The result is a tagged union. For example, we can make a tagged union of the tagged cell types above using `$%`. We'll store this structure using the dojo `=` operation (not a feature of Hoon):
316```
317> =user $%([%employee name=@t full-time=?] [%customer name=@t])
319> `user`[%employee 'John Smith' &]
320[%employee name='John Smith' full-time=%.y]
322> `user`[%employee 'Ryan Jones' |]
323[%employee name='Ryan Jones' full-time=%.n]
325> `user`[%customer 'Sally Williams']
326[%customer name='Sally Williams']
328> `user`[%burglar 'Hamburglar']
329nest-fail
330```
332`$%` is especially useful when you need a composite type of various categories, each of which has a different structure. There is to be a unique tag for each category, which your Hoon program will use to determine how to handle the data appropriately.
334### `$@` Define a Union of Atom and Cell Types
336The `$@` rune takes two subexpressions. The first must be an atomic type, and the second must be a cell type. The result is a union.
338Often `$@` is used to define a type with a null or trivial case for the `@` case. For example, we can expand the `user` structure using `$@` to give it a null case:
340```
341> =user $@(~ $%([%employee name=@t full-time=?] [%customer name=@t]))
343> `user`[%employee 'Ryan Jones' |]
344[%employee name='Ryan Jones' full-time=%.n]
346> `user`[%customer 'Sally Williams']
347[%customer name='Sally Williams']
349> `user`~
351```
353Now the `~` value is included as a possible value for `user`.
355We will see types arise again, in the context of polymorphism in [Lesson 2.5](@/docs/tutorials/hoon/type-polymorphism.md).