on 8bfc8af help sign in
492 lines 12 kB history raw
1+++
2title = "1.5 Lists"
3weight = 8
4template = "doc.html"
5aliases = ["/docs/learn/hoon/hoon-tutorial/lists/"]
6+++
8A **list** is a type of [noun](/docs/glossary/noun/) that you'll frequently encounter when reading and writing Hoon. A list can be thought of as an ordered arrangement of zero or more elements terminated by a `~` (null).
10So a list can be either null or non-null. When the list contains only `~` and no items, it's the null list. Most lists are, however, non-null lists, which have items preceding the `~`. Non-null lists, called _lests_, are cells in which the head is the first list item, and the tail is the rest of the list. The tail is itself a list, and if such a list is also non-null, the head of this sublist is the second item in the greater list, and so on. To illustrate, let's look at a list `[1 2 3 4 ~]` with the cell-delineating brackets left in:
12`[1 [2 [3 [4 ~]]]]`
14It's easy to see where the heads are and where the nesting tails are. The head of the above list is the [atom](/docs/glossary/atom/) `1` and the tail is the list `[2 [3 [4 ~]]]`, (or `[2 3 4 ~]`). Recall that whenever cell brackets are omitted so that visually there appears to be more than two child nouns, it is implicitly understood that the right-most nouns constitute a cell.
16To make a list, let's cast nouns to the `(list @)` ("list of atoms") type.
18```
19> `(list @)`~
22> `(list @)`[1 2 3 4 5 ~]
23~[1 2 3 4 5]
25> `(list @)`[1 [2 [3 [4 [5 ~]]]]]
26~[1 2 3 4 5]
28> `(list @)`~[1 2 3 4 5]
29~[1 2 3 4 5]
30```
32Notice how the last Dojo command has a different construction, with the `~` in front of the bracketed items. This is just another way of writing the same thing; `~[1 2]` is semantically identical to `[1 2 ~]`.
34## An aside about Casting
36The use of casts in this example is helpful to explain to the Hoon compiler exactly what it is we mean with these data structures. In this case, we are telling it they are all lists of atoms. Get in the habit of casting your data structures, as it will not only help anyone reading your code, but it will help you in hunting down bugs in your code.
38Let's make a list whose items are of the `@t` string type:
40```
41> `(list @t)`['Urbit' 'will' 'rescue' 'the' 'internet' ~]
42<|Urbit will rescue the internet|>
43```
45The head of a list has the face `i` and the tail has the face `t`. (For the sake of neatness, these faces aren't shown by the Hoon pretty printer.) To use the `i` and `t` faces of a list, you must first prove that the list is non-null by using the conditional family of runes, `?`:
47```
48> =>(b=`(list @)`[1 2 3 4 5 ~] i.b)
49-find.i.b
50find-fork-d
52> =>(b=`(list @)`[1 2 3 4 5 ~] ?~(b ~ i.b))
55> =>(b=`(list @)`[1 2 3 4 5 ~] ?~(b ~ t.b))
56~[2 3 4 5]
57```
59It's important to note that performing tests like `?~ mylist` will actually transform `mylist` into a `lest`, a non-null list. Because `lest` is a different type than `list`, performing such tests can come back to bite you later in non-obvious ways when you try to use some standard library functions meant for lists.
61You can construct lists of any type. `(list @)` indicates a list of atoms, `(list ^)` indicates a list of cells, `(list [@ ?])` indicates a list of cells whose head is an atom and whose tail is a flag, etc.
63## Tapes and Cords
65While a list can be of any type, there are some special types of lists that are built into Hoon. The `tape` is the most common example.
67Hoon has two kinds of strings: cords and tapes. Cords are atoms with aura `@t`, and they're pretty-printed between `''` marks.
69```
70> 'this is a cord'
71'this is a cord'
73> `@`'this is a cord'
742.037.307.443.564.446.887.986.503.990.470.772
75```
77A tape is a list of `@tD` atoms (i.e., ASCII characters).
79```
80> "this is a tape"
81"this is a tape"
83> `(list @)`"this is a tape"
84~[116 104 105 115 32 105 115 32 97 32 116 97 112 101]
85```
87You can also use the words `cord` and `tape` for casting:
89```
90> `tape`"this is a tape"
91"this is a tape"
93> `cord`'this is a cord'
94'this is a cord'
95```
97## List Functions in the Hoon Standard Library
99Lists are a commonly used data structure. Accordingly, there are several functions in the [Hoon standard library](/docs/reference/library/) intended to make lists easier to use.
101For a complete list of these functions, check out the standard library reference for lists [here](/docs/reference/library/2b/). Here we'll look at a few of these functions.
103### `flop`
105The `flop` function takes a list and returns it in reverse order:
107```
108> (flop ~[11 22 33])
109~[33 22 11]
111> (flop "Hello!")
112"!olleH"
114> (flop (flop "Hello!"))
115"Hello!"
116```
118#### `flop` Exercise 1.5a
120Without using `flop`, write a [gate](/docs/glossary/gate/) that takes a `(list @)` and returns it in reverse order. There is a solution at the bottom of this lesson.
122### `sort`
124The `sort` function uses the "quicksort" algorithm to sort a list. It takes a list to sort and a gate that serves as a comparator. For example, if you want to sort the list `~[37 62 49 921 123]` from least to greatest, you would pass that list along with the `lth` gate (for "less than"):
126```
127> (sort ~[37 62 49 921 123] lth)
128~[37 49 62 123 921]
129```
131To sort the list from greatest to least, use the `gth` gate ("greater than") as the basis of comparison instead:
133```
134> (sort ~[37 62 49 921 123] gth)
135~[921 123 62 49 37]
136```
138You can sort letters this way as well:
140```
141> (sort ~['a' 'f' 'e' 'k' 'j'] lth)
142<|a e f j k|>
143```
145The function passed to `sort` must produce a `flag`, i.e., `?`.
147### `weld`
149The `weld` function takes two lists of the same type and concatenates them:
151```
152> (weld ~[1 2 3] ~[4 5 6])
153~[1 2 3 4 5 6]
155> (weld "Happy " "Birthday!")
156"Happy Birthday!"
157```
159#### `weld` Exercise 1.5b
161Without using `weld`, write a gate that takes a `[(list @) (list @)]` of which the product is the concatenation of these two lists. There is a solution at the bottom of this lesson.
163### `snag`
165The `snag` function takes an atom `n` and a list, and returns the `n`th item of the list, where `0` is the first item:
167```
168> (snag 0 `(list @)`~[11 22 33 44])
16911
171> (snag 1 `(list @)`~[11 22 33 44])
17222
174> (snag 3 `(list @)`~[11 22 33 44])
17544
177> (snag 3 "Hello!")
178'l'
180> (snag 1 "Hello!")
181'e'
183> (snag 5 "Hello!")
184'!'
185```
187Note: there is currently a type system issue that causes some of these functions to fail when passed a list `b` after some type inference has been performed on `b`. For an illustration of the bug, let's set `b` to be a `(list @)` of `~[11 22 33 44]` in the Dojo:
189```
190> =b `(list @)`~[11 22 33 44]
192> b
193~[11 22 33 44]
194```
196Now let's use `?~` to prove that `b` isn't null, and then try to `snag` it:
198```
199> ?~(b ~ (snag 0 b))
200nest-fail
201```
203The problem is that `snag` is expecting a raw list, not a list that is known to be non-null.
205You can cast `b` to `(list)` to work around this:
207```
208> ?~(b ~ (snag 0 `(list)`b))
20911
210```
212#### `snag` Exercise 1.5c
214Without using `snag`, write a gate that returns the `n`th item of a list. There is a solution at the bottom of this lesson.
216### `oust`
218The `oust` function takes a pair of atoms `[a=@ b=@]` and a list, and returns the list with `b` items removed, starting at item `a`:
220```
221> (oust [0 1] `(list @)`~[11 22 33 44])
222~[22 33 44]
224> (oust [0 2] `(list @)`~[11 22 33 44])
225~[33 44]
227> (oust [1 2] `(list @)`~[11 22 33 44])
228~[11 44]
230> (oust [2 2] "Hello!")
231"Heo!"
232```
234### `lent`
236The `lent` function takes a list and returns the number of items in it:
238```
239> (lent ~[11 22 33 44])
242> (lent "Hello!")
244```
246#### `lent` Exercise 1.5d
248Without using `lent`, write a gate that takes a list and returns the number of item in it. There is a solution at the bottom of this lesson.
250### `roll`
252The `roll` function takes a list and a gate, and accumulates a value of the list items using that gate. For example, if you want to add or multiply all the items in a list of atoms, you would use `roll`:
254```
255> (roll `(list @)`~[11 22 33 44 55] add)
256165
258> (roll `(list @)`~[11 22 33 44 55] mul)
25919.326.120
260```
262### `turn`
264The `turn` function takes a list and a gate, and returns a list of the products of applying each item of the input list to the gate. For example, to add `1` to each item in a list of atoms:
266```
267> (turn `(list @)`~[11 22 33 44] |=(a=@ +(a)))
268~[12 23 34 45]
269```
271Or to double each item in a list of atoms:
273```
274> (turn `(list @)`~[11 22 33 44] |=(a=@ (mul 2 a)))
275~[22 44 66 88]
276```
278`turn` is Hoon's version of Haskell's `map`.
280We can rewrite the [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) program using `turn`:
282```hoon
283|= [a=@ b=tape]
284^- tape
285?: (gth a 25)
286 $(a (sub a 26))
287%+ turn b
288|= c=@tD
289?: &((gte c 'A') (lte c 'Z'))
290 =. c (add c a)
291 ?. (gth c 'Z') c
292 (sub c 26)
293?: &((gte c 'a') (lte c 'z'))
294 =. c (add c a)
295 ?. (gth c 'z') c
296 (sub c 26)
298```
300## Using `hoon.hoon` to Learn Hoon
302The Hoon standard library and compiler are written in Hoon. At this point, you know enough Hoon to be able to explore the standard library portions of `hoon.hoon` and find more functions relevant to lists. Look around in [section 2b](/docs/reference/library/2b/) (and elsewhere).
304## Additional Exercises
306#### Exercise 1.5e
308Without entering these expressions into the Dojo, what are the products of the following expressions?
310```
311> (lent ~[1 2 3 4 5])
312```
314```
315> (lent ~[~[1 2] ~[1 2 3] ~[2 3 4]])
316```
318```
319> (lent ~[1 2 (weld ~[1 2 3] ~[4 5 6])])
320```
322#### Exercise 1.5f
324First, bind these faces.
326```
327> =b ~['moon' 'planet' 'star' 'galaxy']
328> =c ~[1 2 3]
329```
331Then determine whether the following Dojo expressions are valid, and if so, what they evaluate to.
333```
334> (weld b b)
335```
337```
338> (weld b c)
339```
341```
342> (lent (weld b c))
343```
345```
346> (add (lent b) (lent c))
347```
349#### Exercise 1.5g
351Write a gate that takes in a list `a` and returns `%.y` if `a` is a palindrome and `%.n` otherwise. You may make use of the `flop` function.
353## Exercise Solutions
355#### 1.5a `flop`
357```hoon
358:: flop.hoon
359::
360|= a=(list @)
361=| b=(list @)
362|- ^- (list @)
363?~ a b
364$(b [i.a b], a t.a)
365```
367Run in Dojo:
369```
370> +flop ~[11 22 33 44]
371~[44 33 22 11]
372```
374#### 1.5b `weld`
376```hoon
377:: weld.hoon
378::
379|= [a=(list @) b=(list @)]
380|- ^- (list @)
381?~ a b
382[i.a $(a t.a)]
383```
385Run in Dojo:
387```
388> +weld [~[1 2 3] ~[3 4 5 6]]
389~[1 2 3 3 4 5 6]
390```
392#### 1.5c `snag`
394```hoon
395:: snag.hoon
396::
397|= [a=@ b=(list @)]
398?~ b !!
399?: =(0 a) i.b
400$(a (dec a), b t.b)
401```
403Run in Dojo:
405```
406> +snag [0 ~[11 22 33 44]]
40711
409> +snag [2 ~[11 22 33 44]]
41033
411```
413#### 1.5d `lent`
415```hoon
416:: lent.hoon
417::
418|= a=(list)
419^- @
420=/ b=@ 0
421|-
422?~ a b
423$(a t.a, b +(b))
424```
426Run in Dojo:
428```
429> +lent ~[1 2 3 4 5]
431> +lent "asdf"
433```
435#### 1.5e
437Run in Dojo:
439```
440> (lent ~[1 2 3 4 5])
442> (lent ~[~[1 2] ~[1 2 3] ~[2 3 4]])
444> (lent ~[1 2 (weld ~[1 2 3] ~[4 5 6])])
446```
448#### 1.5f
450Run in Dojo:
452```
453> (weld b b)
454<|moon planet star galaxy moon planet star galaxy|>
455```
457```
458> (weld b c)
459```
461This will not run because `weld` expects the elements of both lists to be of the same type.
463```
464> (lent (weld b c))
465```
467This also fails for the same reason, but it is important to note that in some languages that are more lazily evaluated, such an expression would still work since it would only look at the length of `b` and `c` and not worry about what the elements were. In that case, it would return `7`.
469```
470> (add (lent b) (lent c))
472```
474We see here the correct way to find the sum of the length of two lists of unknown type.
476#### 1.5g
478```hoon
479:: palindrome.hoon
480::
481|= a=(list)
482=(a (flop a))
483```
485Run in Dojo:
487```
488> +palindrome "urbit"
489%.n
490> +palindrome "racecar"
491%.y
492```