@@ -31,51 +31,57 @@ demonstrates important principles that more laconic code would not. Save it as
34−|= [msg=tape key=@ud]
34+|= [msg=tape steps=@ud]
36=. msg (cass msg)
36=. msg (cass msg)
37−:- (shift msg key)
37+:- (shift msg steps)
38−(unshift msg key)
38+(unshift msg steps)
40++ alpha "abcdefghijklmnopqrstuvwxyz"
41++ alpha "abcdefghijklmnopqrstuvwxyz"
42− |= [message=tape key=@ud]
43+ |= [message=tape shift-steps=@ud]
43− (operate message key (encoder key))
45+ (operate message (encoder shift-steps))
45− |= [message=tape key=@ud]
47+ |= [message=tape shift-steps=@ud]
46− (operate message key (decoder key))
49+ (operate message (decoder shift-steps))
53+ =/ value-tape=tape (rotation alpha steps)
54+ (space-adder alpha value-tape)
58+ =/ value-tape=tape (rotation alpha steps)
59+ (space-adder value-tape alpha)
48− |= [message=tape key=@ud encoder=(map @t @t)]
61+ |= [message=tape shift-map=(map @t @t)]
50 %+ turn message
63 %+ turn message
52− (~(got by encoder) a)
65+ (~(got by shift-map) a)
53−++ encoder
66+++ space-adder
54− |= [key=@ud]
67+ |= [key-position=tape value-result=tape]
55− =/ keytape=tape (rott alpha key)
68+ ^- (map @t @t)
56− (coder alpha keytape)
69+ (~(put by (map-maker key-position value-result)) ' ' ' ')
57−++ decoder
70+++ map-maker
59− =/ keytape=tape (rott alpha key)
60− (coder keytape alpha)
63− (~(put by (zipper a b)) ' ' ' ')
65− |= [a=tape b=tape]
71+ |= [key-position=tape value-result=tape]
66 ^- (map @t @t)
72 ^- (map @t @t)
67 =| chart=(map @t @t)
73 =| chart=(map @t @t)
68− ?. =((lent a) (lent b))
74+ ?. =((lent key-position) (lent value-result))
69 ~| %uneven-lengths !!
75 ~| %uneven-lengths !!
71− ?: |(?=(~ a) ?=(~ b))
77+ ?: |(?=(~ key-position) ?=(~ value-result))
73− $(chart (~(put by chart) i.a i.b), a t.a, b t.b)
79+ $(chart (~(put by chart) i.key-position i.value-result), key-position t.key-position, value-result t.value-result)
75− |= [m=tape n=@ud]
81+ |= [my-alphabet=tape my-steps=@ud]
76− =/ length=@ud (lent m)
82+ =/ length=@ud (lent my-alphabet)
77− =+ s=(trim (mod n length) m)
83+ =+ (trim (mod my-steps length) my-alphabet)
78− (weld q.s p.s)
84+ (weld q p)
@@ -87,6 +93,9 @@ that has been shifted left. It also converts any uppercase input into lowercase.
87Try it out in the Dojo:
93Try it out in the Dojo:
96+> +caesar ["abcdef" 1]
90> +caesar ["test" 2]
99> +caesar ["test" 2]
91["vguv" "rcqr"]
100["vguv" "rcqr"]
@@ -115,30 +124,30 @@ itself before reading the explanation.
118−|= [msg=tape key=@ud]
127+|= [msg=tape steps=@ud]
122The `!:` in the first line of the above code enables a full stack trace in the
131The `!:` in the first line of the above code enables a full stack trace in the
123event of an error.
132event of an error.
125−`|= [msg=tape key=@ud]` creates a [gate](/docs/glossary/gate/) that takes a cell. The head of this cell
134+`|= [msg=tape steps=@ud]` creates a [gate](/docs/glossary/gate/) that takes a cell. The head of this cell
126is a `tape`, which is a string type that's a list of `cord`s. Tapes are represented
135is a `tape`, which is a string type that's a list of `cord`s. Tapes are represented
127as text surrounded by double-quotes, such as this: `"a tape"`. We give this input
136as text surrounded by double-quotes, such as this: `"a tape"`. We give this input
128tape the face `msg`. The tail of our cell is a `@ud` -- an unsigned decimal [atom](/docs/glossary/atom/)
137tape the face `msg`. The tail of our cell is a `@ud` -- an unsigned decimal [atom](/docs/glossary/atom/)
129−-- that we give the face `key`.
138+-- that we give the face `steps`.
131`=<` is the rune that evaluates its first child expression with respect to its
140`=<` is the rune that evaluates its first child expression with respect to its
132second child expression as the subject. In this case, we evaluate the
141second child expression as the subject. In this case, we evaluate the
133expressions in the code chunk below against the [core](/docs/glossary/core/) declared later, which
142expressions in the code chunk below against the [core](/docs/glossary/core/) declared later, which
134allows us reference the core's contained [arms](/docs/glossary/arm/) before they are defined. Without
143allows us reference the core's contained [arms](/docs/glossary/arm/) before they are defined. Without
135−`=<`, we would need to put the code chunk below at the bottom of our program.
144+`=<`, we would need to put the code chunk below at the bottom of our program. In Hoon, as previously
145+stated, we always want to keep the longer code towards the bottom of our programs - `=<` helps us do that.
138=. msg (cass msg)
148=. msg (cass msg)
139−:- (shift msg key)
149+:- (shift msg steps)
140−(unshift msg key)
150+(unshift msg steps)
144`=. msg (cass msg)` changes the input string `msg` to lowercases. `=.` changes
153`=. msg (cass msg)` changes the input string `msg` to lowercases. `=.` changes
@@ -146,137 +155,165 @@ the leg of the subject to something else. In our case, the leg to be changed is
146`msg`, and the thing to replace it is `(cass msg)`. `cass` is a standard-library
155`msg`, and the thing to replace it is `(cass msg)`. `cass` is a standard-library
147gate that converts uppercase letters to lowercase.
156gate that converts uppercase letters to lowercase.
149−`:- (shift msg key)` and `(unshift msg key)` simply composes a
158+`:- (shift msg steps)` and `(unshift msg steps)` simply composes a
150−cell of a right-shifted cipher and a left-shifted cell. This is the final output
159+cell of a right-shifted cipher and a left-shifted cipher of our original message.
160+We will see how this is done using the core described below, but this is the final
151−of our generator.
161+output of our generator.
153−`|%` creates a core.
163+`|%` creates a `core`, the second child of `=<`. Everything after `|%` is part of that
164+second child `core`, and will be used as the subject of the first child of `=<`, described
165+above. The various parts, or `arm`s, of the `core` are denoted by `++` beneath it, for
156− ++ rott
169+ ++ rotation
157− |= [m=tape n=@ud]
170+ |= [my-alphabet=tape my-steps=@ud]
158− =/ length=@ud (lent m)
171+ =/ length=@ud (lent my-alphabet)
159− =+ s=(trim (mod n length) m)
172+ =+ (trim (mod my-steps length) my-alphabet)
160− (weld q.s p.s)
173+ (weld q p)
163−The `rott` arm takes takes a specified number of characters off of a tape and
176+The `rotation` arm takes takes a specified number of characters off of a tape and
164−puts them on the end of the tape.
177+puts them on the end of the tape. We're going to use this to create our shifted alphabet,
178+based on the number of `steps` given as an argument to our gate.
166−`|= [m=tape n=@ud]` creates a gate that takes two arguments: `m`, a `tape`,
180+`|= [my-alphabet=tape my-steps=@ud]` creates a gate that takes two arguments: `my-alphabet`, a `tape`,
167−and `n`, a `@ud`.
181+and `my-steps`, a `@ud`.
169−`=/ length=@ud (lent m)` stores the length of `m` to make the following
183+`=/ length=@ud (lent my-alphabet)` stores the length of `my-alphabet` to make the following
170code a little clearer.
184code a little clearer.
172`trim` is a a gate from the standard library that splits a tape at into two
186`trim` is a a gate from the standard library that splits a tape at into two
173−parts at a specified position. So `=+ s=(trim (mod n length) m)` splits the
187+parts at a specified position. So `=+ (trim (mod my-steps length) my-alphabet)` splits the
174−tape `m` into two parts, `p` and `q`, and stores it in `s`. We call the modulus
188+tape `my-alphabet` into two parts, `p` and `q`, which are now directly available in the subject.
175−operation `mod` to make sure that we split our `tape` at the correct place, even
189+We call the modulus operation `mod` to make sure that the point at which we split our `tape` is
176−if `n` is larger than `length`.
190+a valid point inside of `my-alphabet` even if `my-steps` is greater than `length`, the length of
191+`my-alphabet`. Try trim in the dojo:
197+> (trim 4 "yourbeard")
178−`(weld q.s p.s)` uses `weld`, which combines two strings into one. In this
201+`(weld q p)` uses `weld`, which combines two strings into one. Remember that `trim` has given us
179−instance, we are switching the two parts: the second part `q.s` is welded to the
202+a split version of `my-alphabet` with `p` being the front half that was split off of `my-alphabet`
203+and `q` being the back half. Here we are welding the two parts back together, but in reverse order:
180−front, and the first part `p.s` is welded to the back.
204+the second part `q` is welded to the front, and the first part `p` is welded to the back.
183− ++ zipper
207+ ++ map-maker
184− |= [a=tape b=tape]
208+ |= [key-position=tape value-result=tape]
185 ^- (map @t @t)
209 ^- (map @t @t)
186 =| chart=(map @t @t)
210 =| chart=(map @t @t)
187− ?. =((lent a) (lent b))
211+ ?. =((lent key-position) (lent value-result))
188− ~| %uneven-lengths !!
212+ ~| %uneven-lengths !!
190− ?: |(?=(~ a) ?=(~ b))
214+ ?: |(?=(~ key-position) ?=(~ value-result))
192− $(chart (~(put by chart) i.a i.b), a t.a, b t.b)
216+ $(chart (~(put by chart) i.key-position i.value-result), key-position t.key-position, value-result t.value-result)
195−The `zipper` arm takes two tapes and creates a `map` out of them -- an
219+The `map-maker` arm, as the name implies, takes two tapes and creates a [`map`](/docs/reference/library/2o/#map) out of them.
196−association between their elements.
220+A `map` is a type equivalent to a dictionary in other languages: it's a data structure that
197−
221+associates a key with a value. If, for example, we wanted to have an association
198−So then if `tapes` are easier to manipulate, why then are we producing `cords`?
222+between `a` and 1 and `b` and 2, we could use a `map`.
199−In this case what we are going to to be doing is mapping a single element of a `
200−tape` to another element of a `tape`, which as we have established as being a
201−`cord`. This will simplify our use of this method and we don't need to
202−manipulate the keys or values, simply look them up.
204`|= [a=tape b=tape]` builds a gate that takes two tapes, `a` and `b`, as its
224`|= [a=tape b=tape]` builds a gate that takes two tapes, `a` and `b`, as its
207−`^- (map @t @t)` casts the gate to a `map` with a `cord` key and a `cord`
227+`^- (map @t @t)` casts the gate to a `map` with a `cord` (or `@t`) key and a `cord`
208−value. A `map` is a type equivalent to a dictionary in other languages: it's a
228+value.
209−data structure that associates a key with a value. If, for example, we wanted
229+
210−to have an association between `a` and 1 and `b` and 2, we could use a `map`.
230+You might wonder, if our gate in this arm takes `tape`s, why then are we producing
231+a map of `cord` keys and values?
233+As we discussed earlier, a `tape` is a list of `cord`s. In this case what we are going to do
234+is map a single element of a `tape` (either our alphabet or shifted-alphabet) to an element of
235+a different `tape` (either our shifted-alphabet or our alphabet). This pair will therefore be
236+a pair of `cord`s. When we go to use this `map` to convert our incoming `msg`, we will take
237+each element (`cord`) of our `msg` `tape`, use it as a `key` when accessing our `map` and get
238+the corresponding `value` from that position in the `map`. This is how we're going to encode
239+or decode our `msg` `tape`.
212`=| chart=(map @t @t)` adds a [noun](/docs/glossary/noun/) to the subject with the default value of
241`=| chart=(map @t @t)` adds a [noun](/docs/glossary/noun/) to the subject with the default value of
213the `(map @t @t)` type, and gives that noun the face `chart`.
242the `(map @t @t)` type, and gives that noun the face `chart`.
215−`?. =((lent a) (lent b))` checks if the two tapes are the same length. If not,
244+`?. =((lent key-position) (lent value-result))` checks if the two `tape`s are the same length. If not,
216−the program crashes.
245+the program crashes with an error message of `%uneven-lengths`, using `|~ %uneven-lengths !!`.
247+If the two `tape`s are of the same length, we continue on to create a trap.
218`|-` creates a [trap](/docs/glossary/trap/), a gate that is called immediately.
248`|-` creates a [trap](/docs/glossary/trap/), a gate that is called immediately.
220−`?: |(?=(~ a) ?=(~ b))` checks if either tape is empty. If this is true, we
250+`?: |(?=(~ key-position) ?=(~ value-result))` checks if either `tape` is empty. If this is true, the
221−the program is finished and can return `chart`, the the `map` that we have been
251+`map-maker` arm is finished and can return `chart`, the the `map` that we have been
224−If the above test finds that its condition to be false, we trigger a recursion
254+If the above test finds that the `tape`s are not empty, we trigger a recursion
225that constructs our `map`: `$(chart (~(put by chart) i.a i.b), a t.a, b t.b)`.
255that constructs our `map`: `$(chart (~(put by chart) i.a i.b), a t.a, b t.b)`.
226−This code recursively adds an entry in our `map` where the head of the tape `a`
256+This code recursively adds an entry in our `map` where the head of the `tape` `a`
227−maps to the value of the head of tape `b` with `~(put by chart)`, our calling
257+maps to the value of the head of `tape` `b` with `~(put by chart)`, our calling
228−of the `put` arm of the `by` map-engine core. The recursion also "consumes"
258+of the `put` arm of the `by` map-engine core (note that `~(<wing> <door> <sample>`) is
259+a shorthand for `%~ <wing> <door> <sample>` (see the [Calls % ('cen')](/docs/reference/hoon-expressions/rune/cen/#censig)
260+documentation for more information). The recursion also "consumes"
229−those heads with every iteration by changing `a` and `b` to their tails.
261+those heads with every iteration by changing `a` and `b` to their tails using `a t.a, b t.b`.
231−Perhaps now you can understand why this arm is named `zipper`. It's putting two
232−tapes together by matching pieces from each side, something akin to a jacket zipper.
234−We have three related arms to look at next, `coder`, `encoder`, and
263+We have three related arms to look at next, `decoder`, `encoder`, and
235−`decoder`. `coder` is the foundation of the other two, so we'll look at it
264+`space-adder`. `space-adder` is required for the other two, so we'll look at it
239− ++ coder
268+ ++ space-adder
240− |= [a=tape b=tape]
269+ |= [key-position=tape value-result=tape]
241− (~(put by (zipper a b)) ' ' ' ')
270+ ^- (map @t @t)
271+ (~(put by (map-maker key-position value-result)) ' ' ' ')
244−`|= [a=tape b=tape]` creates a gate that takes two `tapes`.
274+`|= [key-position=tape value-result=tape]` creates a gate that takes two `tapes`.
246−We use `put by` on the next line, giving it a `map` produced by the `zipper`
276+We use the `put` arm of the `by` core on the next line, giving it a `map` produced
247−arm that we created before. This adds an entry to the map where the space
277+by the `map-maker` arm that we created before as its sample. This adds an entry to the
248−character (called `ace`) simply maps to itself. This is done to simplify
278+map where the space character (called `ace`) simply maps to itself. This is done to
249−the handling of spaces in `tapes` we want to encode, since we don't want to
279+simplify the handling of spaces in `tapes` we want to encode, since we don't want to
250shift them.
280shift them.
253 ++ encoder
283 ++ encoder
254− |= [key=@ud]
284+ |= [steps=@ud]
255− =/ keytape=tape (rott alpha key)
285+ ^- (map @t @t)
256− (coder alpha keytape)
286+ =/ value-tape=tape (rotation alpha steps)
287+ (space-adder alpha value-tape)
257 ++ decoder
288 ++ decoder
258− |= [key=@ud]
289+ |= [steps=@ud]
259− =/ keytape=tape (rott alpha key)
290+ ^- (map @t @t)
260− (coder keytape alpha)
291+ =/ key-tape=tape (rotation alpha steps)
292+ (space-adder key-tape alpha)
263−`encoder` and `decoder` are implemented in terms of the `coder` arm. These gates
295+`encoder` and `decoder` utilize the `rotation` and `space-adder` arms. These gates
264−are essentially identical, with the arguments reversed. They simplify the two
296+are essentially identical, with the arguments passed to `rotation` reversed. They
265−common transactions you want to do in this program: producing `maps` that we can
297+simplify the two common transactions you want to do in this program: producing `maps`
266−use to encode and decode messages.
298+that we can use to encode and decode messages.
300+In both cases, we create a gate that accepts a `@ud` named `steps`.
268−In both cases, we create a gate that accepts a `@ud` named `key`.
302+In `encoder`:
303+`=/ value-tape=tape (rotation alpha steps)` creates a `value-tape` noun by calling `rotation`
304+on `alpha`. `alpha` is our arm which contains a `tape` of the entire alphabet. The
305+`value-tape` will be the list of `value`s in our `map`.
270−`=/ keytape=tape (rott alpha key)` creates a `keytape` noun by calling `rott`
307+In `decoder`:
271−on `alpha` our `key` input. `alpha` is our arm which contains a `tape` of the
308+`=/ key-tape (rotation alpha steps)` does the same work, but when passed to `space-adder`
272−entire alphabet.
309+it will be the list of `key`s in our `map`.
274−`(coder alpha keytape)`, for `encoder`, and `(coder keytape alpha)`, for
311+`(space-adder alpha value-tape)`, for `encoder`, and `(space-adder key-tape alpha)`, for
275`decoder`, produce a `map` that has the first argument as the keys and the
312`decoder`, produce a `map` that has the first argument as the keys and the
276second as the values.
313second as the values.
278−If our two inputs to `coder` were `"abcdefghijklmnopqrstuvwxyz"` and
315+If our two inputs to `space-adder` were `"abcdefghijklmnopqrstuvwxyz"` and
279−`"bcdefghijklmnopqrstuvwxyza"` We would get a `map` where `'a'` maps to `'b'`,
316+`"bcdefghijklmnopqrstuvwxyza"`, we would get a `map` where `'a'` maps to `'b'`,
280`'b'` to `'c'` and so on. By doing this we can produce a `map` that gives us a
317`'b'` to `'c'` and so on. By doing this we can produce a `map` that gives us a
281translation between the alphabet and our shifted alphabet, or vice versa.
318translation between the alphabet and our shifted alphabet, or vice versa.
@@ -285,30 +322,32 @@ walked through.
288− |= [message=tape key=@ud]
325+ |= [message=tape shift-steps=@ud]
289− (operate message key (encoder key))
327+ (operate message (encoder shift-steps))
290 ++ unshift
328 ++ unshift
291− |= [message=tape key=@ud]
329+ |= [message=tape shift-steps=@ud]
292− (operate message key (decoder key))
331+ (operate message (decoder shift-steps))
295Both `shift` and `unshift` take two arguments: our `message`, the `tape` that we
334Both `shift` and `unshift` take two arguments: our `message`, the `tape` that we
296−want to manipulate; and our `key`, the value that we want to shift our message
335+want to manipulate; and our `shift-steps`, the number of positions of the alphabet
297−by.
336+by which we want to shift our message.
299`shift` is for encoding, and `unshift` is for decoding. Thus, `shift` calls the
338`shift` is for encoding, and `unshift` is for decoding. Thus, `shift` calls the
300−`operate` arm with `(operate message key (encoder key))`, and `unshift` makes
339+`operate` arm with `(operate message (encoder shift-steps))`, and `unshift` makes
301−that call with `(operate message key (decoder key))`. These both produce the
340+that call with `(operate message (decoder shift-steps))`. These both produce the
302−final output of the core, to be called in the form of `(shift msg key)`
341+final output of the core, to be called in the form of `(shift msg steps)`
303−and `(unshift msg key)` at the bottom of the program.
342+and `(unshift msg steps)` in the cell being created at the beginning of our code.
306−++ operate
345+ ++ operate
307− |= [message=tape key=@ud encoder=(map @t @t)]
346+ |= [message=tape shift-map=(map @t @t)]
309− %+ turn message
348+ %+ turn message
311− (~(got by encoder) a)
350+ (~(got by shift-map) a)
314`operate` produces a `tape`. The `%+` rune allows us to pull an arm
353`operate` produces a `tape`. The `%+` rune allows us to pull an arm
@@ -316,6 +355,12 @@ with a pair sample. The arm we are going to pull is `turn`. This arm
316takes two arguments, a `list` and a `gate` to apply to each element of the
355takes two arguments, a `list` and a `gate` to apply to each element of the
358+In this case, the `gate` we are applying to our `message` uses the `got` arm
359+of the `by` door with our `shift-map` as the sample (which is either the standard alphabet
360+for keys, and the shifted alphabet for values, or the other way, depending on
361+whether we are encoding or decoding) to look up each `cord` in our `message`, one by one
362+and replace it with the `value` from our `map` (either the encoded or decoded version).
319If we then give our arm Caesar's famous statement, and get our left- and
364If we then give our arm Caesar's famous statement, and get our left- and
320right-ciphers.
365right-ciphers.
@@ -340,8 +385,10 @@ look for the legible result.
3401. Take the example generator and modify it to add a second layer of shifts.
3851. Take the example generator and modify it to add a second layer of shifts.
3422. Extend the example generator to allow for use of characters other than a-z.
3872. Extend the example generator to allow for use of characters other than a-z.
388+ Make it shift the new characters independently of the alpha characters, such
389+ that punctuation is only encoded as other punctuation marks.
344−3. Build a gate that can take a Caesar shifted `tape` and produce
391+3. Build a gate that can take a Caesar shifted `tape` and produce all
345−possible unshifted `tapes`.
392+ possible unshifted `tapes`.
3474. Modify the example generator into a `%say` generator.
3944. Modify the example generator into a `%say` generator.