Lesson 9 – North by Northwest


Introduction


In this lesson we’re going to add a new tool to your toolkit: maps. Maps are pairs of values that can be used as lookup tables - if you know one value of a pair, you can request the other, and vice versa.
We’re going to introduce you to some new Standard Library functions to manipulate maps, but there are many more map functions available than what we’ll get to here. You will be asked to read the map functions in the rest of Urbit’s documentation.
You should be ready to start writing your own generators and experimenting with new standard library functions at this point.

Goal

Write a simple generator that takes a number and returns one of 5 phrases, from a map of numbers-to-phrases.

Runes/Standard Library


%- cen·hep

SyntaxSummary
%- gate hoonevalute a gate
(gate hoon)

%- Evalutes a gate

%- takes two children:

  • The first child is a wing resolution which evalutes to a gate (this may be a gate from the standard library.)
  • The second child is some hoon, which will be used as the gate's sample.

It is quite common to see %- in its irregular form as (gate hoon).

Documentation on urbit.org

Note that we have already encountered %- in its irregular form, for example in (add 1 2).

Exercise

Try this in dojo:

=tester |=(a=tape (flop a))
%-  tester  "tape"
"epat"

The same call using irregular form:

(tester "tape")
"epat"

Let's clear 'tester' from our subject before moving on.

=tester


%~ cen·sig

SyntaxSummary
%~ arm door hoon hoon .. hoon ==Evaluate an arm in a door.
~(arm door hoon hoon .. hoon)

%~ Evaluates an arm in a door.
A door is a sort of core which has one or more arms and takes a sample. (A gate is a trivial case of door, with only one arm, $.)
When %~ is used, which we'll often see as in its irregular form as ~(arm door hoon hoon ..), all of the hoon expressions will be taken as the sample for evaluation the specified arm.

Documentation on urbit.org

Exercise

Try this in dojo:

=tester |_  a=_"this is a tape"
++  flopper  (flop a)
--
%~  flopper  tester  "tape"
"epat"

The same call using irregular form:

~(flopper tester "tape")
"epat"

Again, let's clear 'tester' from our subject before moving on.

=tester

Note: In this lesson, we will be using arms from the door "by" from hoon.hoon . This is a "type-polymorphic" door that handles maps. Type polymorphism, from our early perspective, simply means that the door and its arms can handle maps of different types. For example, maps of @uds to tapes are allowable, as are maps of @tas to @rs, and so on.

my

SyntaxSummary
(my [[a b] [c d] .. [y z] ~])Produce a map from list of key:value pairs.

Standard Library function that takes a null terminated list of ordered pairs and produces a map of key:value pairs.


There are numerous circumstances in which it is useful to be able to look up a reference value (key) and return another result value that has been associated with it. In Hoon, maps allow for this sort of lookup, got arm from the by core, which takes a map and key and produces a value at the given key position

+-got:by

SyntaxSummary
(~(got by m) 'a')Produce the value located at key b within map a.

Produce the value located at key ‘b’ within map ‘a’.


Example Generator


|=  find=@ud
|^
^-  cord
(~(got by mymap) find)
::  
++  mymap
  %-  my
  :~  :-  1  'sibilance'
      :-  2  'alabaster'
      :-  3  'Rotterdam'
      :-  4  'BSV is Bitcoin'
      :-  5  'I am not a number, I am a free man'
  ==
--

Walkthrough

  • |=
    |= creates a gate, taking two arguments, a type specification and some hoon to evaluate.

    • find=@ud
      Our input sample must have the type @ud, and is assigned the face 'find’
    • |^
      |^ creates a core with one arm(named $) which will be computed immediately, and at least one other arm

      • ^-
        ^- takes two children, a type and some hoon expression. This ^- expression constitutes our $ arm and ^- is casting its output.

        • cord
          First child of ^-, our type specification, indicating that the product of the following expression must be cast to cord.
        • (~(got by mymap) find)
          Second child of ^-, the hoon to be evaluated.
          (~(got by mymap) find) is a call to the got arm from the by core mentioned above, which deals with maps. got takes in a 'map' and 'key' and produces the 'value' associated with the given 'key'.
          Here we are looking for the key identified by the value given in our sample, with face 'find'.
    • ++ mymap
      ++ marks the definition of an arm given the name mymap. This arm will evaluate to the product of the following expression.

      • %-
        %- evaluates a gate and takes two children, the gate itself, and some hoon to be taken as the sample.

        • my
          The first child of %-, the my gate from the standard library.
        • :~ :~ creates a null terminated list, of indeterminate length, which must be closed by ==.
          • :- :- creates an ordered pair of:1 and 'sibilance’.
          • :- :- creates an ordered pair of: 2 and 'alabaster’
          • :- :- creates an ordered pair of: 3 and 'rotterdam’
          • :- :- creates an ordered pair of: 4 and 'BSV is Bitcoin’
          • :- :- creates an ordered pair of: 5 and 'I am not a number, I am a free man’
          • == The == boundary closes our :~ expression.
    • --
      The - - boundary indicates the closing of our |^ core.

Flow

  1. Request an input of an @ud and form a gate
    |=  find=@ud
  2. Form a core with one arm named $ which will be evaluated immediately, and at least one other arm (in this case, named 'mymap')
    |^
  3. Cast the output as a cord
    ^-  cord
  4. Use the arm got of the door by to find, from the map called mymap (which is an arm of this core) the value that is paired to the key represented by the face find
    (~(got by mymap) find)
    Note that although the $ arm above will be evaluated immediately, the other arms of the core are compiled even before that evaluation. That is, the remaining steps are processed before Steps 3 and 4, which produce our output.
  5. Define an arm called mymap
    ++  mymap
  6. The arm called mymap uses the function my, which takes a null terminated cell of ordered pairs and makes a map. :~ creates a null terminated cell.
      %-  my
      :~  :-  1  'sibilance’
          :-  2  'alabaster’
          :-  3  'rotterdam’
          :-  4  'BSV is Bitcoin’
          :-  5  'I am not a number, I am a free man’
      ==
  7. Inside of %- my, :~ creates a null terminated cell of the cells created by :-, which will look like the following, which is the exactly the format the gate "my" expects, to make a map of keys and values:[[1 'sibilance’] [2 'alabaster’] [3 'rotterdam’] [4 'BSV is Bitcoin’] [5 'I am not a number, I am a free man’] ~]
  8. (See Step 4)Return the value (second item in the pair) of the cell represented by the key (first item in the pair) that is the same as the atom identified by the face find

Readings

Homework

  1. Read and understand the Caesar Cipher code walkthrough, reading 1.7.1 above.
  2. Do exercise 2, from the same reading:
    • Extend the example generator to allow for use of characters other than a-z.
    • Bonus: Make it shift the new characters independently of the alpha characters by character set, such that punctuation is only encoded as other punctuation and numbers are only encoded as other numbers.
  3. Do exercise 3, from the same reading.
    • Build a gate that can take a Caesar shifted tape and produce all possible unshifted tapes.
    • This should be performed using the original a-z only cipher.

Bring any questions you have about this generator to Office Hours, or submit those questions with your homework.