on c5260eb help sign in
153 lines 5.8 kB history raw
1+++
2title = "Libraries"
3weight = 0
4template = "doc.html"
5+++
7As in other languages, it's often very useful in hoon to create a library for your code. Let's take a look at one example of a library for dealing with playing cards.
9```
10|%
11+$ suit ?(%hearts %spades %clubs %diamonds)
12+$ darc [sut=suit val=@ud]
13+$ deck (list darc)
14++ make-deck
15 ^- deck
16 =| mydeck=deck
17 =/ i 1
18 |-
19 ?: (gth i 4)
20 mydeck
21 =/ j 1
22 |-
23 ?. (lte j 13)
24 ^$(i +(i))
25 %= $
26 j +(j)
27 mydeck [(num-to-suit i) j]^mydeck
28 ==
29++ num-to-suit
30 |= val=@ud
31 ^- suit
32 ?+ val !!
33 %1 %hearts
34 %2 %spades
35 %3 %clubs
36 %4 %diamonds
37 ==
38++ shuffle-deck
39 |= [unshuffled=deck entropy=@]
40 ^- deck
41 =| shuffled=deck
42 =/ random ~(. og entropy)
43 =/ remaining (lent unshuffled)
44 |-
45 ?: =(remaining 1)
46 :_ shuffled
47 (snag 0 unshuffled)
48 =^ index random (rads:random remaining)
49 %^ $
50 shuffled (snag index unshuffled)^shuffled
51 remaining (dec remaining)
52 unshuffled (oust [index 1] unshuffled)
53++ draw
54 |= [n=@ud d=deck]
55 ^- [hand=deck rest=deck]
56 :- (scag n d)
57 (slag n d)
58--
59```
61After creating a core, we use the `+$` arm to create three types we're going to need.
63```
64+$ suit ?(%hearts %spades %clubs %diamonds)
65+$ darc [sut=suit val=@ud]
66+$ deck (list darc)
67```
69The first is `suit` which can be one of `%hearts`, `%spades`, `%clubs`, or `%diamonds`.
71Next is a `darc` which is a pair of `suit` and an `@ud` which is a numeric value for the card. Why is it called `darc` and not `card`? `card` already has a meaning in gall where we are likely to use this library so it's worth while to avoid any name confusion in the future.
73Our final type is `deck` which is simply a `list` of `darc`
75One way to get a feel for how a library works is to skim the arm names before diving into any specific arm. In this library, the arms are `make-deck`, `num-to-suit`, `shuffle-deck`, and `draw`. In this case, these names should be very clear with the exception of `num-to-suit` though you could probably hazard a guess at what it does. Let's take a closer look at that one first.
77```
78++ num-to-suit
79 |= val=@ud
80 ^- suit
81 ?+ val !!
82 %1 %hearts
83 %2 %spades
84 %3 %clubs
85 %4 %diamonds
86 ==
87```
89We can see this is a gate that takes a single `@ud` and produces a `suit`.
91The `?+` rune is the rune to switch against a value with a default. The default here is to crash with `!!`. Then we have the four possible options 1-4 which each result in a suit.
93```
94++ draw
95 |= [n=@ud d=deck]
96 ^- [hand=deck rest=deck]
97 :- (scag n d)
98 (slag n d)
99```
101`draw` takes two arguments, `n` a number and `d` a `deck`. It's going to produce a cell of two `decks` the first contains a hand of `n` `darcs` and the second is the rest of the `deck`. This is done with the `scag` and `slag` gates.
103```
104++ shuffle-deck
105 |= [unshuffled=deck entropy=@]
106 ^- deck
107 =| shuffled=deck
108 =/ random ~(. og entropy)
109 =/ remaining (lent unshuffled)
110 |-
111 ?: =(remaining 1)
112 :_ shuffled
113 (snag 0 unshuffled)
114 =^ index random (rads:random remaining)
115 %^ $
116 shuffled (snag index unshuffled)^shuffled
117 remaining (dec remaining)
118 unshuffled (oust [index 1] unshuffled)
119```
121Finally we come to `shuffle-deck`. This gate takes two arguments, a `deck` and a `@` as a bit of `entropy` to seed the `og` core. It's going to produce a `deck`.
123`=|` adds a defaulted `deck` to the subject.
125Next we feed the `og` core the entropy it needs in preparation for using it and we get the length of the unshuffled deck with `lent`.
127If we have only one card remaining, we produce a cell of `shuffled` and that one card left in `unshuffled` with the `:_` rune so we can have the heavier twig to the bottom of the expression.
129Else we are going to do a little work. `=^` is a rune that pins the head of a pair and changes the leg with a tail. It's useful for interacting with the `og` core arms as many of them produce a pair of a random number and the next state of the core. We're going to put the random number in the subject with the face `index` and change `random` to be the next core.
131That completed, we use `%^` to call `$` to recurse back up to the `|-` with a few changes.
133`shuffled` gets the `darc` from `unshuffled` at `index` added to the front of it.
135`remaining` gets decremented. Why are we using a counter here instead of just checking the length of `unshuffled` on each loop? `lent` traverses the entire list every time it's called so maintaining a counter in this fashion is much faster.
137`unshuffled` becomes the result of using `oust` to remove 1 `darc` at `index` on `unshuffled`.
139This is a very naive shuffling algorithm and you could imagine a better one. Implementation of a better algorithm is left as an exercise for the reader.
141So now that we have this library, how do we actually use it? Let's look at a very simple `say` generator that uses it.
143```
144/+ playing-cards
145:- %say
146|= [[* eny=@uv *] *]
147:- %noun
148(shuffle-deck:playing-cards make-deck:playing-cards eny)
149```
151If you save this in the `gen` directory and the library as `playing-cards.hoon` in the `lib` directory, you can import the library with the `/+` rune. This is not a hoon rune, but instead a rune used by Ford, the Urbit build system. When this file gets built, Ford will pull in the requested library and also build it. It will also create a dependency so that if `playing-cards.hoon` changes, this file will also get rebuilt.
153Here you have the standard `say` generator boilerplate that allows us to get a bit of entropy from `arvo` when the generator is run. Then we feed that and a `deck` created by `make-deck` into `shuffle-deck` to get back a shuffled `deck`.