17Genr

nock is easy! - http://www.urbit.org

Jan 20th, 2014
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.50 KB | None | 0 0
  1.  
  2. logo
  3. Urbit
  4.  
  5. An operating function
  6.  
  7. Documentation
  8. Blog
  9. Community
  10. Follow:
  11. Y
  12.  
  13. Urbit Is Easy: Chapter II (Intro To Nock)
  14.  
  15. Prev: Setup Next: Nock Is Easy
  16.  
  17. “What one fool can do, another can” (Ancient Simian proverb)
  18.  
  19. Now that we’ve installed Arvo, let’s learn Nock.
  20.  
  21. Think of Nock as a kind of functional assembly language. It’s not like assembly language in that it’s directly executed by the hardware. It is like assembly language in that (a) everything in Urbit executes as Nock; (b) you wouldn’t want to program directly in Nock; and (c) learning to program directly in Nock is a great way to start understanding Urbit from the ground up.
  22.  
  23. Just as Unix runs C programs by compiling them to assembler, Urbit runs Hoon programs by compiling them to Nock. You could try to learn Hoon without learning Nock. But just as C is a thin wrapper over the physical CPU, Hoon is a thin wrapper over the Nock virtual machine. It’s a tall stack made of thin layers, which is much easier to learn a layer at a time.
  24.  
  25. And unlike most fundamental theories of computing, there’s really nothing smart or interesting about Nock. Of course, in a strictly formal sense, all of computing is math. But that doesn’t mean it needs to feel like math. Nock is a simple mechanical device and it’s meant to feel that way.
  26. Specification
  27.  
  28. Let’s start with the Nock spec. It may look slightly intimidating, but at least it isn’t long.
  29.  
  30. No, you can’t just look at this and tell what it’s doing. But at least there are only 39 lines of it.
  31.  
  32. 1 :: A noun is an atom or a cell.
  33. 2 :: An atom is a natural number.
  34. 3 :: A cell is an ordered pair of nouns.
  35. 4 ::
  36. 5 :: nock(a) *a
  37. 6 :: [a b c] [a [b c]]
  38. 7 ::
  39. 8 :: ?[a b] 0
  40. 9 :: ?a 1
  41. 10 :: +[a b] +[a b]
  42. 11 :: +a 1 + a
  43. 12 :: =[a a] 0
  44. 13 :: =[a b] 1
  45. 14 :: =a =a
  46. 15 ::
  47. 16 :: /[1 a] a
  48. 17 :: /[2 a b] a
  49. 18 :: /[3 a b] b
  50. 19 :: /[(a + a) b] /[2 /[a b]]
  51. 20 :: /[(a + a + 1) b] /[3 /[a b]]
  52. 21 :: /a /a
  53. 22 ::
  54. 23 :: *[a [b c] d] [*[a b c] *[a d]]
  55. 24 ::
  56. 25 :: *[a 0 b] /[b a]
  57. 26 :: *[a 1 b] b
  58. 27 :: *[a 2 b c] *[*[a b] *[a c]]
  59. 28 :: *[a 3 b] ?*[a b]
  60. 29 :: *[a 4 b] +*[a b]
  61. 30 :: *[a 5 b] =*[a b]
  62. 31 ::
  63. 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
  64. 33 :: *[a 7 b c] *[a 2 b 1 c]
  65. 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
  66. 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
  67. 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
  68. 37 :: *[a 10 b c] *[a c]
  69. 38 ::
  70. 39 :: *a *a
  71.  
  72. Bear in mind: this is pseudocode. It is neither Nock nor Hoon. Strictly speaking, it’s really just English. All formal systems resolve to informal language at the very bottom. What’s important is just that no two reasonable people can read the spec to mean two different things.
  73. Sounds
  74.  
  75. In characteristic Urbit style, we got tired of three or four-syllable pronunciations of ASCII punctuation characters and assigned them all standard one-syllable names. We’ll meet the rest later, but the ones we use in Nock:
  76.  
  77. `$` buc
  78. `/` fas
  79. `+` lus
  80. `(` pel
  81. `)` per
  82. `[` sel
  83. `]` ser
  84. `*` tar
  85. `=` tis
  86. `?` wut
  87.  
  88. Nouns
  89.  
  90. Let’s look at the data model first - lines 1-3 above. Ideally, you can look at this and just tell what it’s doing. But let’s explain it a little anyway.
  91.  
  92. An atom is a natural number - ie, an unsigned integer. Nock does not limit the size of atoms, or know what an atom means.
  93.  
  94. For instance, the atom 97 might mean the number 97, or it might mean the letter ‘a’ (ASCII 97). A very large atom might be the number of grains of sand on the beach - or it might be a GIF of your children playing on the beach. Typically when we represent strings or files as atoms, the first byte is the low byte. But even this is just a convention. An atom is an atom.
  95.  
  96. A cell is an ordered pair of any two nouns - cell or atom. We group cells with square brackets:
  97.  
  98. [1 1]
  99. [34 45]
  100. [[3 42] 12]
  101. [[1 0] [0 [1 99]]]
  102.  
  103. To keep our keyboards from wearing out, line 6 tells us that brackets group to the right:
  104.  
  105. 6 :: [a b c] [a [b c]]
  106.  
  107. So instead of writing
  108.  
  109. [2 3]
  110. [2 [6 7]]
  111. [2 [6 [14 15]]]
  112. [2 [6 [[28 29] [30 31]]]]
  113. [2 [6 [[28 29] [30 [62 63]]]]]
  114.  
  115. we can write
  116.  
  117. [2 3]
  118. [2 6 7]
  119. [2 6 14 15]
  120. [2 6 [28 29] 30 31]
  121. [2 6 [28 29] 30 62 63]
  122.  
  123. While this notational convenience is hardly rocket science, it’s surprising how confusing it can be, especially if you have a Lisp background. Lisp’s “S-expressions” are very similar to nouns, except that Lisp has multiple types of atom, and Lisp’s syntax automatically adds list terminators to groups. So in Lisp
  124.  
  125. '(2 6 7)
  126.  
  127. is a shorthand for
  128.  
  129. '(2 6 7 . nil)
  130.  
  131. and the equivalent noun is
  132.  
  133. [2 6 7 0]
  134.  
  135. or, of course,
  136.  
  137. [2 [6 [7 0]]]
  138.  
  139. Rules
  140.  
  141. A Nock program is given meaning by a process of reduction. To compute Nock(x), where x is any noun, we step through the rules from the top down, find the first left-hand side that matches x, and reduce it to the right-hand side.
  142.  
  143. Right away we see line 5:
  144.  
  145. 5 :: Nock(a) *a
  146.  
  147. When we use variable names, like a, in the pseudocode spec, we simply mean that the rule fits for any noun a.
  148.  
  149. So Nock(x) is *x, for any noun x. And how do we reduce *x? Looking up, we see that lines 23 through 39 reduce *x - for different patterns of x.
  150.  
  151. For example, suppose our x is [5 1 6]. Stepping downward through the rules, the first one that matches is line 26:
  152.  
  153. 26 :: *[a 1 b] b
  154.  
  155. Line 26 tells us that when reducing any noun of the form [a 1 b], the result is just b. So *[5 1 6] is 6.
  156.  
  157. For a more complicated example, try
  158.  
  159. *[[19 42] [0 3] 0 2]
  160.  
  161. The first rule it matches is line 23:
  162.  
  163. 23 :: *[a [b c] d] [*[a b c] *[a d]]
  164.  
  165. since a is [19 42], b is 0, c is 3, and d is [0 2]. So this reduces to a new computation
  166.  
  167. [*[[19 42] 0 3] *[[19 42] 0 2]]
  168.  
  169. Each side of this matches rule 25:
  170.  
  171. 25 :: *[a 0 b] /[b a]
  172.  
  173. So we have
  174.  
  175. [/[3 [19 42]] /[2 [19 42]]]
  176.  
  177. When we explain /, we’ll see that this is [42 19].
  178.  
  179. Finally, suppose our x is just 42. The first rule that matches is the last:
  180.  
  181. 39 :: *a *a
  182.  
  183. So *42 is *42, which is *42. Logically, Nock goes into an infinite reduction loop and never terminates.
  184.  
  185. In practice, this is just a clever CS way to specify the simple reality that *42 is an error and makes no sense. An actual interpreter will not spin forever - it will throw an exception outside the computation.
  186. Functions
  187.  
  188. We’ve already seen the * function (pronounced “tar”), which just means Nock. This is the main show and we’ll work through it soon, but first let’s explain the functions it uses - =, ?, + and /.
  189. Equals: =
  190.  
  191. = (pronounced “tis”, or sometimes “is”) tests a cell for equality. 0 means yes, 1 means no:
  192.  
  193. 12 :: =[a a] 0
  194. 13 :: =[a b] 1
  195. 14 :: =a =a
  196.  
  197. Again, testing an atom for equality makes no sense and logically fails to terminate.
  198. Depth: ?
  199.  
  200. ? (pronounced “wut”) tests whether is a noun is a cell. Again, 0 means yes, 1 means no:
  201.  
  202. 8 :: ?[a b] 0
  203. 9 :: ?a 1
  204.  
  205. (This convention is the opposite of old-fashioned booleans, so we try hard to say “yes” and “no” instead of “true” and “false.”)
  206. Increment: +
  207.  
  208. + (pronounced “lus”, or sometimes “plus”) adds 1 to an atom:
  209.  
  210. 10 :: +[a b] +[a b]
  211. 11 :: +a 1 + a
  212.  
  213. Because + works only for atoms, whereas = works only for cells, the error rule matches first for + and last for =.
  214. Address: /
  215.  
  216. / (pronounced “fas”) is a tree address function:
  217.  
  218. 16 :: /[1 a] a
  219. 17 :: /[2 a b] a
  220. 18 :: /[3 a b] b
  221. 19 :: /[(a + a) b] /[2 /[a b]]
  222. 20 :: /[(a + a + 1) b] /[3 /[a b]]
  223. 21 :: /a /a
  224.  
  225. This looks way more complicated than it is. Essentially, we define a noun as a binary tree - where each node branches to a left and right child - and assign an address, or axis, to every element in the tree. The root of the tree is /1. The left child of every node at /a is /2a; the right child is /2a+1. (Writing (a + a) is just a clever way to write 2*a, while minimizing the set of pseudocode forms.)
  226.  
  227. For a complete tree of depth 3, the axis address space looks like this:
  228.  
  229. 1
  230. 2 3
  231. 4 5 6 7
  232. 8 9 10 11 12 13 14 15
  233.  
  234. Let’s use the example [[97 2] [1 42 0]]. So
  235.  
  236. /[1 [97 2] [1 42 0]] [[97 2] [1 42 0]]
  237.  
  238. because /1 is the root of the tree, ie, the whole noun. Then its left child is /2 (ie, (1 + 1)):
  239.  
  240. /[2 [97 2] [1 42 0]] [97 2]
  241.  
  242. And its right child is /3 (ie, (1 + 1 + 1)):
  243.  
  244. /[3 [97 2] [1 42 0]] [1 42 0]
  245.  
  246. And delving into /3, we see /(3 + 3) and (3 + 3 + 1):
  247.  
  248. /[6 [97 2] [1 42 0]] 1
  249. /[7 [97 2] [1 42 0]] [42 0]
  250.  
  251. If this seems like rocket science, the problem may be that you’re too smart to understand Nock. Forget everything you learned in school and start over from line 1.
  252.  
  253. It’s also fun to build nouns in which every atom is its own axis:
  254.  
  255. 1
  256. [2 3]
  257. [2 6 7]
  258. [[4 5] 6 7]
  259. [[4 5] 6 14 15]
  260. [[4 5] [12 13] 14 15]
  261. [[4 [10 11]] [12 13] 14 15]
  262. [[[8 9] [10 11]] [12 13] 14 30 31]
  263.  
  264. Once you’ve spent enough time programming in Urbit, you’ll know these axes in your dreams. No - really.
  265.  
  266. Prev: Setup Next: Nock Is Easy
  267.  
  268. © Urbit, 2013 — built with Jekyll using Lagom theme
Add Comment
Please, Sign In to add comment