on master help sign in
Merge pull request #150 from keatondunsford/push-to-www-again

Push to www-ship.

commit58a90fe469825dd65cb116040cbb0deba983575a authorGalen Wolfe-Pauly <galen@office-for.com> dateThu 16 Feb 2017, 11:21 (10 years ago) parente539d725452ba6
34 files changed+3602−17
docs.md+1−1 docs/byte.md+10 docs/byte/0.md+281 docs/byte/1.md+369 docs/byte/2.md+495 docs/community-docs.md+31 docs/community-projects.md+30 docs/community-projects/nock-implementations.md+10 docs/community-projects/nock-implementations/clojure.md+125 docs/community-projects/nock-implementations/csharp.md+478 docs/community-projects/nock-implementations/groovy.md+206 docs/community-projects/nock-implementations/haskell.md+63 docs/community-projects/nock-implementations/hoon.md+54 docs/community-projects/nock-implementations/javascript.md+365 docs/community-projects/nock-implementations/python.md+95 docs/community-projects/nock-implementations/ruby.md+139 docs/community-projects/nock-implementations/scala.md+86 docs/community-projects/nock-implementations/scheme.md+128 docs/community-projects/nock-implementations/swift.md+366 docs/community-projects/string-processing.md+17 docs/community-projects/talkbot.md+17 docs/community-projects/yint.md+17 docs/hoon/advanced.md+1−1 docs/hoon/demo.md+1−1 docs/hoon/examples.md+1−1 docs/hoon/exercises.md+1−1 docs/hoon/irregular.md+1−1 docs/hoon/mission.md+1−1 docs/hoon/reference.md+1−1 docs/hoon/syntax.md+1−1 docs/hoon/troubleshooting.md+1−1 docs/hoon/twig.md+1−1 docs/nock.md−2 docs/nock/implementations.md+209−4
docs.md+1−1
@@ -12,7 +12,7 @@ sort: 4
1212
1313<div class="col-md-12 head">
1414
15−<div class="col-md-8">
15+<div class="col-md-10">
1616
1717**Urbit** is a secure peer-to-peer network of personal servers, built on a clean-slate system software stack.
1818
docs/byte.mdnew file+10
@@ -0,0 +1,10 @@
1+---
2+navhome: /docs/
3+sort: 2
4+---
5+
6+# Learn
7+
8+Learn Hoon in short, self-contained, bottom-up tutorials through our in-house Urbyte series. A work in progress. Still ideal for the complete newbie.
9+
10+<list/>
docs/byte/0.mdnew file+281
@@ -0,0 +1,281 @@
1+---
2+navhome: /docs/
3+sort: 1
4+next: true
5+title: Setup and nouns
6+---
7+
8+# Urbyte 0: Setup and nouns
9+
10+This is the first post in our new Urbyte series.
11+
12+The Urbyte concept is that you, an ordinary programmer, not a
13+kernel hacker or a Haskell magician (not that there's anything
14+wrong with kernel hackers or Haskell magicians) can learn Hoon,
15+Urbit's programming language.
16+
17+We're going to test this daring idea by teaching you Hoon, in
18+easily digestible, byte-size chunks. Each post in the "Urbytes"
19+series is designed to take about 15 minutes to consume. (Maybe
20+10, if you're a kernel hacker or a Haskell magician.)
21+
22+We'll assume no knowledge of Urbit except for previous lessons.
23+Ideally you have some basic familiarity with programming and can
24+operate the Unix command line.
25+
26+We strongly encourage you to type in all the examples in each
27+Urbyte. Urbytes are short, but not meant to be skimmed.
28+
29+## Install
30+
31+First, [install Urbit](http://urbit.org/docs/using/install/) on any
32+Mac or Unix machine. On Windows, make a virtual Linux machine
33+using VirtualBox or a similar tool.
34+
35+While you're downloading, read about Urbit ships:
36+
37+## Ships
38+
39+In the Urbyte exercises you'll be running what we call a "comet". A string starting with `~`, like `~zod`, is what Urbit
40+calls a *ship*.
41+
42+A *ship* is one number which means four things: a network address,
43+a cryptographic identity, a memorable name, and a single virtual
44+computer.
45+
46+We write this number in a base-256 format, where each digit is a
47+syllable. Imagine if your phone number was a pronounceable
48+string which sounded like a name in a foreign language. `~zod`
49+is ship zero (making it a very important ship indeed!). An ordinary
50+user-level ship is a "planet", a 32-bit number which becomes
51+a four-syllable string, like `~talsur-todres`.
52+
53+*Comets*, at 128-bits or 16 syllables, are
54+disposable identities that anyone can make for free to
55+join the live network. Thus, comets make the ideal ship for
56+playing around with Hoon, asking for help from other Urbit devs in [`:talk`](http://urbit.org/docs/using/messaging/) if you
57+need it, and showing off Urbit to your hacker friends.
58+
59+## Create and restart
60+
61+To create your comet, run:
62+
63+```
64+$ cd ~
65+$ mkdir urbit
66+$ cd urbit
67+$ urbit -c mycomet
68+```
69+
70+This will take a few minutes and will spin out a bunch of boot
71+messages. At the end, you'll see something like:
72+
73+```
74+ames: on localhost, UDP 31337.
75+http: live (insecure, public) on 8080
76+http: live ("secure", public) on 8443
77+http: live (insecure, loopback) on 12321
78+~palnul_nocser:dojo>
79+```
80+
81+To make sure everything is working, type `(add 2 2)` at the
82+prompt, then hit return. Your screen now shows:
83+
84+```
85+ames: on localhost, UDP 31337.
86+http: live (insecure, public) on 8080
87+http: live ("secure", public) on 8443
88+http: live (insecure, loopback) on 12321
89+> (add 2 2)
90+4
91+```
92+~palnul_nocser:dojo>
93+
94+That's super awesome! You made your first noun! We'll make a
95+few more in a second. First, quit Urbit with `ctrl-d`:
96+
97+```
98+> (add 2 2)
99+4
100+~palnul_nocser:dojo>
101+$
102+```
103+
104+You now have an Urbit image, or *pier*, in the `mycomet` directory.
105+Right now the only thing in your pier is Urbit's system files:
106+
107+```
108+$ ls -a /path/to/mycomet
109+./ ../ .urb/
110+```
111+
112+Restarting uses almost the same command, but without `-c` (which
113+means "create"). There are also fewer startup messages:
114+
115+```
116+$ urbit mycomet
117+[...]
118+ames: on localhost, UDP 31337.
119+http: live (insecure, public) on 8080
120+http: live ("secure", public) on 8443
121+http: live (insecure, loopback) on 12321
122+~palnul_nocser:dojo>
123+```
124+
125+Note also that Urbit is an ACID database. You can stop it
126+politely with `ctrl-d`, abruptly with `ctrl-z`, even violently with `kill
127+-9`. None of these should cause Urbit to lose data. If you do
128+manage to corrupt a pier, it's a bug; please let us know.
129+
130+## Let's make a noun
131+
132+You've already made a noun. Let's make another!
133+
134+*We won't show the `~palnul_nocser:dojo> ` prompt from here on out.
135+We'll just show the echoed command.*
136+
137+
138+```
139+~palnul_nocser:dojo> 42
140+42
141+```
142+
143+You'll see:
144+
145+```
146+> 42
147+42
148+```
149+
150+## Understanding nouns
151+
152+A value in Urbit is called a *noun*. A noun is either an *atom*
153+(an unsigned integer of any size) or a *cell* (an ordered pair of
154+any two nouns).
155+
156+In a sentence, a noun is a binary tree whose leaves are numbers.
157+If you know Lisp, a noun is a minimalist S-expression. A noun
158+can't have cycles (pointer loops). An implementation can use
159+dags (shared subtrees), but the programmer can't detect them
160+(there's no pointer equality test).
161+
162+The absence of graph cycles makes nouns much easier to save in
163+persistent storage, send over the network, manage memory for
164+(Urbit has no tracing garbage collector), etc.
165+
166+## Let's make some atoms
167+
168+So one kind of atom is a number. And the syntax (or at least one
169+syntax) for a number is a decimal, like `42`. Seems legit.
170+
171+But just to be sure we understand this decimal thing, let's make
172+some atoms:
173+
174+```
175+> 4
176+4
177+```
178+
179+Seems pretty straightforward.
180+
181+```
182+> 42
183+42
184+```
185+
186+Why not try it again to make sure?
187+
188+```
189+> 420
190+420
191+```
192+
193+Can we add another zero?
194+
195+```
196+> 420
197+```
198+
199+Wat? When you tried to type that next zero and turn `420` into
200+`4200`, Urbit actually *deleted the `0` and beeped at you.*
201+
202+But isn't an atom an unsigned integer of any size? It is.
203+But the syntax is actually `4.200`:
204+
205+```
206+> 4.200
207+4.200
208+> (mul 42 100)
209+4.200
210+```
211+
212+Just think of it as "4,200", written the German way with a dot.
213+
214+Why? Long decimals are unreadable. Human beings know this, so
215+we group them in threes. For some historical reason, programming
216+languages never copied this marvelous usability innovation.
217+
218+English notation for decimals is more common than German
219+notation. Unfortunately, dot is URL-safe and comma isn't, and
220+it's nice to have a regular syntax for atoms that's URL-safe.
221+
222+As for why Urbit deleted your zero: it parses your command line
223+as you type, and rejects any characters after the parser stops.
224+
225+## Let's make some cells
226+
227+There's not much mystery about cells. A cell has a head and a
228+tail, and puts brackets around them:
229+
230+```
231+> [42 420]
232+[42 420]
233+```
234+
235+`42` is the *head* and `420` is the *tail* of the cell. Cell
236+syntax nests to the right:
237+
238+```
239+> [4 [42 420]]
240+[4 42 420]
241+
242+> [4 42 420]
243+[4 42 420]
244+
245+> [[4 42] 420]
246+[[4 42] 420]
247+```
248+
249+If you look at these nouns as binary trees, you see
250+
251+```
252+ [4 [42 420]] [[4 42] 420]
253+ . .
254+ / \ / \
255+ 4 . . 420
256+ / \ / \
257+ 42 420 4 42
258+```
259+
260+Each number is an atom; each dot is a cell.
261+
262+## And we're done
263+
264+And we're done! Type `|exit` to exit:
265+
266+```
267+~palnul_nocser:dojo> |exit
268+%drum-exit
269+$
270+```
271+
272+## Questions and/or exercises
273+
274+And we're done with our very first Urbyte! Here's a question to
275+think about. These exercises are never mandatory, but they may
276+be fun and/or interesting. Skip them if they're obvious.
277+
278+The question today is: what is the right way to represent common
279+data structures as nouns? A linked list? A string? A *signed*
280+integer? A table or associative array? Just try to picture
281+these structures in your head, or draw them on a piece of paper.
docs/byte/1.mdnew file+369
@@ -0,0 +1,369 @@
1+---
2+navhome: /docs/
3+sort: 2
4+next: true
5+title: Atoms, auras, types
6+---
7+
8+# Urbyte 1: Atoms, auras, types
9+
10+Thanks for reading Urbyte 0! In Urbyte 1, we'll look a little
11+more deeply at atoms and other simple noun types.
12+
13+Let's restart our engines:
14+
15+```
16+$ urbit mycomet
17+[...]
18+ames: on localhost, UDP 31337.
19+http: live (insecure, public) on 8080
20+http: live ("secure", public) on 8443
21+http: live (insecure, loopback) on 12321
22+~palnul_nocser:dojo>
23+```
24+
25+## What's in an atom?
26+
27+It seems limiting to have only one kind of atom, the unsigned
28+decimal. How are signed integers represented? Symbols?
29+Floating-point values? Dates? IP addresses? Even just hex?
30+
31+Lisp's S-expression, with its own cells and atoms, is very
32+similar to Hoon's nouns. But languages in the Lisp family mark
33+each atom with a dynamic tag that defines the atom's meaning.
34+These tags are effectively dynamic types.
35+
36+Hoon also tracks the meaning of atoms. But Hoon is statically
37+typed, so an atom description is obviously a type. An atomic type
38+in Hoon is called an *aura*. The aura syntax is just an ASCII
39+string starting with `@`, like `@ud` for unsigned decimal.
40+
41+Hoon has a wide (but not extensible) variety of atom syntaxes.
42+Each syntax for an atom produces an appropriate predefined aura.
43+And Hoon's printer can invertibly print any aura Hoon can parse.
44+Because atoms make great path nodes and paths make great URLs,
45+all regular atom syntaxes use only URL-safe characters.
46+
47+## Examples
48+
49+With the dojo command `? expression`, you tell the dojo to print
50+both the product of the expression, and the product's type.
51+
52+Let's type in some aura examples:
53+
54+### Unsigned integers
55+
56+```
57+> 42
58+42
59+
60+> ? 42
61+ @ud
62+42
63+
64+> ? 0x42
65+ @ux
66+0x42
67+
68+> ? (add 0x42 42)
69+ @
70+108
71+
72+> ? `@ud`0x42
73+ @ud
74+66
75+
76+```
77+
78+So decimal is aura `@ud`, hexadecimal is `@ux`. Note the cast
79+syntax, which lets us change the type of an atom, converting hex
80+`0x42` to a decimal `66`.
81+
82+An aura is soft type. The programmer can always insist on how
83+to interpret an atom. Hoon doesn't have "dependent types"; it
84+can't enforce any constraints the aura puts on the atom's value.
85+
86+### Signed integers
87+
88+```
89+> -7
90+-7
91+
92+> ? -7
93+ @sd
94+
95+> --7
96+--7
97+
98+> ? --7
99+ @sd
100+--7
101+
102+> ? (sum:si -7 --7)
103+ @s
104+--0
105+
106+> `@ud`-7
107+13
108+
109+> `@ud`--7
110+14
111+```
112+
113+`--7` means "positive 7." `+7` might have been better, but `+`
114+is not URL-safe.
115+
116+Hoon needs `--` to distinguish positive signed numbers because
117+Hoon's type system doesn't feed back into its parser. The
118+expression itself needs to control whether it's `@sd` or `@ud`.
119+
120+With unlimited atom width, traditional sign extension makes no
121+sense. The sign bit is the low bit. Even atoms are positive,
122+odd atoms are negative.
123+
124+And Hoon has no overloading or type detection; we need to use a
125+different function to add signed integers. We'll always choose
126+slightly clunkier syntax in exchange for much simpler semantics.
127+
128+### Symbols
129+
130+```
131+> ? 'Ürbit'
132+ @t
133+'Ürbit'
134+
135+> ? `@ux`'Ürbit'
136+ @ux
137+0x7469.6272.9cc3
138+
139+> ? ~~Ürbit
140+ @t
141+'Ürbit'
142+
143+> ? ~.urbit
144+ @ta
145+~.urbit
146+
147+> ? `@ux`'foo'
148+ @ux
149+0x6f.6f66
150+```
151+
152+The `@t` aura is UTF-8 text, with the first byte low. Again,
153+Hoon doesn't actually have the power to check statically that
154+your UTF-8 is valid. Auras don't tell you what an atom is, just
155+what you think it is.
156+
157+The familiar single-quote syntax for `@t` is an irregular form of
158+the more unusual `~~` prefix. The `~.` prefix, aura `@ta`, is
159+restricted to lowercase ASCII (a great common denominator). Of
160+course, `~` is URL-safe and `'` is not.
161+
162+### Dates, floats, IP addresses...
163+
164+```
165+> ? now
166+ @da
167+~2016.7.11..01.32.04..2c0d
168+
169+> ? ~h6
170+ @dr
171+~h6
172+
173+> `@ux`~h6
174+ @ux
175+0x5460.0000.0000.0000.0000
176+
177+> ? (add ~h6 now)
178+ @
179+170.141.184.502.236.089.414.812.327.632.537.911.296
180+
181+> `@da`(add ~h6 now)
182+~2016.7.11..07.32.28..842f
183+
184+> ? .3.14
185+ @rs
186+.3.14
187+
188+> ? .127.0.0.1
189+ @if
190+.127.0.0.1
191+```
192+
193+`@da` is a 128-bit absolute date (64 bits for fractions of a
194+second, 64 bits for seconds); `@dr` is a relative date; `@rs` is
195+a single-precision IEEE real; `@if` is an IPv4 address. This is
196+not all Hoon's aura syntax, just a good range of examples.
197+
198+`(add ~h6 now)` is a good example of the use and limits of
199+the aura system. Unlike the signed-integer sum, offsetting a
200+date can use plain atomic addition. But the product of `add` is
201+a flavorless atom with no aura, `@`. So we have to cast it back
202+to an absolute date `@da`.
203+
204+## Auras explained
205+
206+Does an aura represent the units of the atom, its syntax, its
207+semantics, its constraints?
208+
209+Any or all of the above. Programmers can even use their own aura
210+strings, which nothing in Hoon recognizes. The set of syntaxes
211+that Hoon knows how to parse and/or print is fixed. But there
212+are plenty of good reasons to use your own user-defined auras.
213+
214+If your program uses both fortnights and furlongs, Hoon will not
215+parse a user-defined fortnight syntax. It will not print furlongs
216+in the dojo. But the type system will keep you from accidentally
217+passing a furlong to a function that expects a fortnight.
218+
219+Hoon does interpret the aura string in one way: auras specialize
220+to the right. For example, `@u` is any unsigned integer; `@ux`
221+is an unsigned integer that likes to be printed as hex.
222+
223+Hoon's typechecker lets you go up or down the specialization
224+ladder. It complains if you try to move across. For example,
225+`@u` can silently convert into `@ux` or `@ux` into `@u`, but
226+turning `@ud` into `@ux`, `@ux` into `@da`, etc, requires an
227+explicit cast.
228+
229+## Constants, symbols, loobeans and null
230+
231+An atom type isn't just an aura. There's another choice: the
232+type can be *general* and contain all atoms (like the types we've
233+seen above), or *constant* and contain just one atom.
234+
235+A type describes a set of values. While auras may informally
236+describe a format for which not all atoms are valid, any atom can
237+be cast into the aura whether valid or invalid. But in a
238+constant, the type contains just one atom.
239+
240+The regular syntax for an atomic constant is just to put `%` in
241+front of the constant. Like:
242+
243+```
244+> ? 42
245+ @ud
246+42
247+
248+> ? %42
249+ $42
250+%42
251+
252+> ? %~h6
253+ $~h6
254+%~h6
255+```
256+
257+The `$` on the type indicates the constant. Note that constants
258+still have auras; `~h6` (6 hours) is still a `@dr`.
259+
260+## Common irregulars
261+
262+There are a few special forms worth learning early: symbols,
263+null, loobeans, and of course ships:
264+
265+```
266+> ? %foo
267+ $foo
268+%foo
269+
270+> `@ux`%foo
271+0x6f.6f66
272+
273+> .n
274+%.n
275+
276+> |
277+%.n
278+
279+> .y
280+%.y
281+
282+> &
283+%.y
284+
285+> `@ud`&
286+0
287+
288+> ~
289+~
290+
291+> `@ud`~
292+0
293+
294+> ? ~zod
295+ @p
296+~zod
297+
298+> `@ux`~forseg-bolbyn
299+0x885e.8af9
300+```
301+
302+`%symbol` is a constant with aura `@tas` (text, ASCII, symbol).
303+The symbol rules, which are enforced by the Hoon parser but not
304+(as we've discussed) the type system: a symbol is lowercase with
305+infix hyphens ("kebab-case").
306+
307+Loobeans are not true and false, but yes (`.y` or `&`) and no
308+(`.n` or `|`). This is because *yes is zero and no is one*.
309+This makes sense at a certain mathematical level, though it
310+was probably a mistake from a practical perspective.
311+
312+`~` is Hoon's nil: constant `0`, aura `@n`.
313+
314+And of course, `@p` is the phonemic base used for ship names.
315+(It's useful for any kind of memorable number.)
316+
317+## Cells and types
318+
319+Naturally, all these atoms fit neatly into cells, and retain
320+their types within the cells.
321+
322+```
323+> ? [~h6 [.3.14 %foo] 0xdead.beef]
324+ {@dr {@rs $foo} @ux}
325+[~h6 [.3.14 %foo] 0xdead.beef]
326+
327+> `*`[~h6 [.3.14 %foo] 0xdead.beef]
328+[398.449.671.992.126.314.905.600 [1.078.523.331 7.303.014] 3.735.928.559]
329+```
330+
331+Another fun trick is to cast any noun to the `*` type, ie,
332+generic noun. We then know nothing about the noun, so we print
333+all its atoms as decimals.
334+
335+## And we're done
336+
337+And we're done! Type `|exit` to exit:
338+
339+```
340+~palnul_nocser:dojo> |exit
341+%drum-exit
342+$
343+```
344+
345+## Questions and/or exercises
346+
347+As always, these questions are optional and only for fun.
348+
349+We didn't include anywhere near all Hoon's auras or syntaxes in
350+this lesson. It's just a set of examples.
351+
352+Try using the dojo's magic error erasure to stumble around the
353+rest of Hoon's atom syntax. Any string that can't be extended
354+into a valid expression will be trimmed back, with a beep, until
355+it can. Return will beep if the expression is not complete.
356+This feedback is harmless and does not use an electric shock.
357+It enables stochastic reinforcement learning of Hoon syntax.
358+
359+If `~h6` is six hours, how do you write forty-five minutes? Two
360+days, six hours and forty-five minutes?
361+
362+What would you expect the syntax for double-precision float to
363+be? What about base64?
364+
365+Does an absolute date have to include every zillisecond, or can
366+it be pruned to a day or a year?
367+
368+If there's an IP syntax, what about bitcoin addresses? What
369+other auras do you think should be supported?
docs/byte/2.mdnew file+495
@@ -0,0 +1,495 @@
1+---
2+navhome: /docs/
3+sort: 3
4+title: Subject-oriented programming
5+---
6+
7+# Urbyte 2: Subject-oriented programming
8+
9+Thanks for reading Urbytes 0 and 1! In Urbyte 2, we'll take
10+nouns for granted and have some real fun with them.
11+
12+Let's restart our engines:
13+
14+```
15+$ urbit mycomet
16+[...]
17+ames: on localhost, UDP 31337.
18+http: live (insecure, public) on 8080
19+http: live ("secure", public) on 8443
20+http: live (insecure, loopback) on 12321
21+~palnul_nocser:dojo>
22+```
23+
24+## Welcome to the dojo
25+
26+Wait, where are we?
27+
28+We're playing in the Urbit `:dojo`. The dojo is sort of like a
29+cross between a Lisp REPL and the Unix shell. (If you know the
30+Unix shell, the Urbit command line has the same history model and
31+Emacs editing commands.)
32+
33+The dojo has its own command language, which is a superset of
34+Hoon. Any Hoon expression is a command. But not all commands
35+are expressions.
36+
37+(The dojo is not the only command-line app on your Urbit. By
38+default there is one other, `:talk`. Since you're on a fakezod,
39+you can only talk to yourself. If you accidentally press `ctrl-x`,
40+it will put you into `:talk`; press `ctrl-x` again to switch back.)
41+
42+### Dojo variables
43+
44+Like the Unix shell, the dojo has command variables. Type
45+
46+```
47+> =a 42
48+```
49+
50+You've set the dojo variable `a` to the value `42`. The dojo
51+puts this binding in the Hoon subject for expressions to use.
52+So you can write:
53+
54+```
55+> a
56+42
57+
58+> [4 a]
59+[4 42]
60+
61+> ? [4 a]
62+ {@ud @ud}
63+[4 42]
64+```
65+
66+To unbind `a`, just omit the value:
67+
68+```
69+> =a
70+```
71+
72+You removed `a` from the subject. (We can bind it again later, or
73+bind over it without removing it.)
74+
75+```
76+> [4 a]
77+-find.a
78+```
79+
80+Now trying to use `a` is an error.
81+
82+## Subject-oriented programming
83+
84+What is this *subject* thing, anyway? We put `a` in what?
85+
86+Most programming languages have something called a *scope* or an
87+*environment* or a *context*. This is a data structure that
88+contains the variables and functions an expression can use.
89+
90+In a normal language, the environment is not a first-class value.
91+You cannot save an environment in a variable, compute an
92+expression against the environment in the variable, etc, etc.
93+
94+In Hoon or any "subject-oriented" language, an expression is
95+executed against one normal value, the *subject*. In Hoon, of
96+course, the subject is a noun.
97+
98+## First experiments
99+
100+Up to now, we've only built constants. By definition, a constant
101+doesn't use the subject.
102+
103+It would be nice to start with the subject every dojo expression
104+gets. But that subject is pretty complex. Instead, let's make a
105+simple noun from the kinds of atoms we've already learned about:
106+
107+```
108+> =a [42 [%foo .6.28 ~m45] 0xdead.beef]
109+
110+> ? a
111+ {@ud {$foo @rs @dr} @ux}
112+[42 [%foo .3.14 ~m45] 0xdead.beef]
113+
114+> 420:a
115+420
116+```
117+
118+The syntax `expression:expression` uses the product of the second
119+expression as the subject of the first. So we're using `a` as
120+the subject of the expression `420`.
121+
122+Of course, `420` is a constant expression. It doesn't care what
123+the subject is. But:
124+
125+```
126+> (add 2 2):a
127+-find.add
128+```
129+
130+We can't use `a` as the subject of even a simple addition. How
131+could we? There's no `add` function in our `a`. It sometimes
132+takes new Hoon programmers a little while before they realize
133+that there really isn't a scope or environment in Hoon.
134+
135+## Tree geometry
136+
137+So what can we do with this subject? How can we get data out of
138+it? Let's keep working with our little test subject `a`.
139+
140+The most basic way to access the subject is *tree geometry*.
141+Every noun is a binary tree; every noun in the tree has a number
142+which is its address. The root of the tree is `1`; if the
143+address of a cell is `n`, its head is `2n` and its tail is
144+`2n+1`.
145+
146+A picture might help:
147+```
148+ 1
149+ / \
150+ 2 3
151+ / \ / \
152+ 4 5 6 7
153+ / \
154+ 14 15
155+```
156+
157+The syntax for a fragment of the subject at a tree address, or
158+*axis*, is just `+axis`. So:
159+
160+```
161+> +3:a
162+[[%foo .3.14 ~m45] 0xdead.beef]
163+
164+> ? +7:a
165+ @ux
166+0xdead.beef
167+
168+> ? +13:a
169+ {@rs @dr}
170+[.3.14 ~m45]
171+```
172+
173+Of course, the fragment retains the type it had when we built it.
174+
175+## Labeled surfaces
176+
177+We can obviously get anything we want out of the subject by tree
178+geometry. But that's not really how we'd like to program. We'd
179+much rather *label* subtrees with convenient, memorable symbols.
180+
181+For example, suppose our tree looked like:
182+
183+```
184+ 1
185+ / \
186+ x=2 3
187+ / \
188+ y=6 z=7
189+ / \
190+ p=14 15
191+ / \
192+ q=30 r=31
193+```
194+
195+Then instead of writing `+2`, we could write `x`, and so on.
196+
197+Let's replace our test subject `a` with a new noun built around
198+this tree of *labeled surfaces*.
199+
200+```
201+> =a [x=42 y=[p=%foo q=.6.28 r=~m45] z=0xdead.beef]
202+
203+> ? x:a
204+ @ud
205+42
206+
207+> ? y:a
208+ {p/$foo q/@rs r/@dr}
209+[p=%foo q=.6.28 r=~m45]
210+
211+> ? q.y:a
212+ @rs
213+.6.28
214+```
215+
216+Surfaces might remind you of attributes in an object. But again,
217+attributes in an object are a symbol table. There is no symbol
218+table here -- just a tree search.
219+
220+An expression like the label `x` or the axis `+2`, which
221+designates a fragment or feature of the subject, is called a
222+*limb*. A list of limbs connected with `.` is a *wing*.
223+
224+To remind you that you're not in Kansas anymore, the syntax for a
225+wing, like `q.y` above, means means "q inside y." In a classic
226+object-oriented system, of course, this would be written `y.q`,
227+that is, attribute `q` within object `y`. In Hoon, `q.y` means
228+"find limb `y`, then find limb `q` inside that."
229+
230+## Surfaces versus fragments
231+
232+Once again, Hoon has no symbol tables. When we put a surface
233+on a noun, the surface label is part of that noun's type. It's
234+not part of the cell or other structure that contains the noun.
235+This will take a little getting used to:
236+
237+```
238+> ? x:a
239+ @ud
240+42
241+
242+> ? +2:a
243+ x/@ud
244+x=42
245+
246+? x.+2:a
247+ @ud
248+42
249+```
250+
251+When we take fragment 2 of the labeled subject, the *surface
252+comes with it*. `+2` is not `42` but rather `x=42`. We can
253+take the surface off with `x.+2`.
254+
255+## The search algorithm
256+
257+In resolving a label to a fragment axis, we search the subject
258+type in a depth-first traverse.
259+
260+If we find a surface that matches the limb, we succeed. If we
261+find a surface that doesn't match the limb, we fail. If we find
262+a cell, we search first head, then tail.
263+
264+## Skipping
265+
266+What if the same label appears twice in one noun? Let's modify
267+our subject slightly as a test case:
268+
269+```
270+> ? +7:a
271+ z/@ux
272+z=0xdead.beef
273+
274+> =a a(+7 x=z:a)
275+
276+> ? a
277+ {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}
278+[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
279+
280+> ? x:a
281+ @ud
282+42
283+
284+> ? ^x:a
285+ @ux
286+0xdead.beef
287+```
288+
289+We don't want to hide any part of the noun from an expression.
290+So the modified limb `^x` *skips* the first match with a surface
291+`x`, getting us to our `0xdead.beef`. This is a unary notation:
292+`^^x` would skip the first two matches.
293+
294+## Editing
295+
296+Above, we mutated our first noun with the flashy `a(+7 x=z:a)`.
297+
298+Of course we are not really "modifying" a noun. Hoon is a pure
299+language. We are making an edited copy. `a(+7 x=z:a)` means "a
300+copy of `a`, with limb `+7` replaced by the product of `x=z:a`."
301+
302+We can edit multiple (disjoint) wings in one expression:
303+
304+```
305+> ? a(+7 [%hello %world], q.y .3.14)
306+ {x/@ud y/{p/$foo q/@rs r/@dr} $hello $world}
307+[x=42 y=[p=%foo q=.3.14 r=~m45] %hello %world]
308+```
309+
310+Notice that nothing stopped us from changing `+7` from
311+`x=0xdead.beef` to `[%hello %world]`. Since the mutated
312+copy is a different noun, it has a different type.
313+
314+(And remember that since `[x y z]` means `[x [y z]]`,
315+`[x y [%hello %world]]` means `[x y %hello %world]`.)
316+
317+## Cores and arms
318+
319+It should be reasonably clear how Hoon's system of fragments and
320+surfaces parallels variables, records or structures in a
321+classical language. But where is Hoon's equivalent of objects:
322+values which bind code to data?
323+
324+The Hoon equivalent of an object is a *core*. As usual in Hoon,
325+the resemblance is inexact. A core has a set of computed
326+attributes, or *arms*. Each arm is an expression whose subject
327+is the core. There is no argument, so an arm is not a method.
328+
329+Physically, a core is always a cell `[battery payload]`, where
330+the *payload* is any noun, and the *battery* is a tree of
331+formulas in Nock (Hoon's functional assembly language) that
332+implements the arms. (A battery is like a C++ vtable, sort of.)
333+
334+## The search algorithm
335+
336+As you'd expect with a computed attribute, there is only one
337+namespace and one search algorithm. We just extend the algorithm
338+described above. And an expression which uses a label can't know
339+whether the subject will resolve it to a surface fragment (a
340+*leg*) or to an arm.
341+
342+If we're searching a core and the label matches one of the core's
343+arms, we compute the arm against the core. If the label is not
344+found, we search into the payload of the core.
345+
346+## Some core examples
347+
348+When you type these examples, make sure you get the number of
349+spaces exactly right. Hoon syntax is not whitespace-sensitive
350+in general, except that "one space" is always a different token
351+from "two or more spaces."
352+
353+```
354+> ? x:a
355+ @ud
356+42
357+
358+> ? :per a x
359+ @ud
360+42
361+
362+> =b :per a :core ++ foo x ++ bar [q.y foo] --
363+```
364+
365+We're seeing some Hoon regular forms for the first time. `x:a`
366+turns out to be an irregular relative of the regular `:per` form.
367+
368+We'll get more into syntax in a later Urbyte. If some of these
369+examples seem syntactically a little funky, this isn't usually
370+way we'd do them in "real life." We don't normally write cores
371+on a single command line. In a file this would be:
372+
373+```
374+ :per a
375+ :core
376+ ++ foo x
377+ ++ bar [q.y foo]
378+ --
379+```
380+
381+which is much more readable, at least once you get used to it.
382+Let's look at the core itself:
383+
384+```
385+> b
386+<2.spy {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}>
387+
388+> ? +2:b
389+ *
390+[[0 6] [0 58] 9 4 0 1]
391+
392+> ? +3:b
393+ {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}
394+[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
395+```
396+
397+When we print `b`, or any core, we see that typed noun printing
398+can't be an invertible function in Hoon.
399+
400+We actually can read the battery (with `+2:b` above), but it's
401+just Nock code, not typed data. `<2.spy>` tells us the battery
402+has two arms and hashes to the three-letter code `spy`.
403+
404+When printing a full core, we don't even print the payload data,
405+just its type. But our `+3:b` confirms the `[battery payload]`
406+structure of the core. Remember, `+2` is the head and `+3` is
407+the tail.
408+
409+Finally, let's use this thing:
410+
411+```
412+> ? foo:b
413+ @ud
414+42
415+
416+> ? bar:b
417+ {@rs @ud}
418+[.6.28 42]
419+
420+? x:b
421+ @ud
422+42
423+```
424+
425+Seems legit.
426+
427+## The dojo subject
428+
429+Now that we've made a test subject which is a core, we can look
430+directly at the real dojo subject:
431+
432+```
433+> +1
434+[ [ [ a=[x=42 y=[p=%foo q=.6.28 r=~m45] x=0xdead.beef]
435+ b=<2.spy {x/@ud y/{p/$foo q/@rs r/@dr} x/@ux}>
436+ ]
437+ now=~2016.7.18..08.05.15..0b5c
438+ eny=0vl.hsfrh.tg642.g5o21.1n80b.0h141.0vuan.pm8o4.77ovg.96rk0.n26nn
439+ our=~palnul-wolmev-bonfex-danred--tilwen-midlux-bolfus-nocser
440+ ]
441+ ~
442+ <283.xzp 42.ajz 407.xtr 110.xht 1.ztu $151>
443+]
444+```
445+
446+We see a bunch of surfaces: our custom `a` and `b`; standard
447+surfaces for identity, date, and entropy; and a ginormous core
448+stack with *over eight hundred* total arms.
449+
450+To be exact, the syntax `<283.xzp 42.ajz 407.xtr 110.xht 1.ztu
451+$151>` denotes a stack of six cores, each of whose payload is
452+another core, until the innermost payload `%151` (the Hoon
453+version number). This stack is our standard library, from which
454+comes `add` and other fine functions. (We don't know how to
455+write a Hoon function yet, but we're getting way closer.)
456+
457+Let's clean up our subject, just to be hygienic:
458+
459+```
460+> =a
461+> =b
462+
463+> +1
464+ now=~2016.7.18..08.10.42..36a0
465+ eny=0vf.8j71j.hlqim.k340u.q0ual.v2cd8.cfa65.vkbte.e733g.ehihg.e8aog
466+[ [ our=~palnul-wolmev-bonfex-danred--tilwen-midlux-bolfus-nocser
467+ ]
468+ ~
469+ <283.xzp 42.ajz 407.xtr 110.xht 1.ztu $151>
470+]
471+```
472+
473+Again, remember that `=a` is not Hoon syntax, but `:dojo` syntax.
474+How the dojo assembles this subject remains a mystery. But it's
475+not a particularly interesting mystery.
476+
477+## And we're done
478+
479+And we're done! Type `|exit` to exit:
480+
481+```
482+~palnul_nocser:dojo> |exit
483+%drum-exit
484+$
485+```
486+
487+## Questions and/or exercises
488+
489+As always, these questions are optional and only for fun.
490+
491+What's the best way to construct a core which acts as a function?
492+What do you do to call the function?
493+
494+Why don't any other languages use subject-oriented programming?
495+Which languages are most similar to it?
docs/community-docs.mdnew file+31
@@ -0,0 +1,31 @@
1+---
2+navhome: /docs/
3+sort: 7
4+---
5+
6+
7+# Community docs
8+
9+<div>
10+
11+<ul>
12+
13+<li><code>~master-morzod</code>
14+<br />
15+<a href="https://micnus-tarwyl-haltem-linhut--dilhul-talbes-wolnyx-lasbud.urbit.org/docs/">docs</a>, <code>fora</code> <a href="https://urbit.org/fora/posts/~2016.12.25..06.35.44..a1ec~/">post</a></li>
16+
17+<li><code>~hidduc-posmeg</code>
18+<br />
19+<a href="https://fosnut-dandut.urbit.org/pages/hidducs-notes/tutorial/docs/">docs</a>, <code>fora</code> <a href="https://urbit.org/fora/posts/~2017.2.12..21.54.40..6fde~/">post</a></li>
20+
21+<li><code>~palfun-foslup</code>
22+<br />
23+<a href="https://github.com/Fang-/Urbit-By-Doing">Urbit by Doing</a></li>
24+
25+<li><code>@knubie</code>
26+<br />
27+<a href="https://github.com/knubie/learning-hoon">Learning Hoon</a></li>
28+
29+</ul>
30+
31+</div>
docs/community-projects.mdnew file+30
@@ -0,0 +1,30 @@
1+---
2+navhome: /docs/
3+sort: 8
4+---
5+
6+
7+# Community projects
8+
9+<div>
10+
11+<ul>
12+
13+<li><a href="https://github.com/ponnys-podfer/yint">Yint: A Tiny MUD</a>
14+<br />
15+<code>~ponnys-podfer</code></li>
16+
17+<li><a href="https://github.com/Fang-/talkbot">~talkbot</a>
18+<br />
19+<code>~palfun-foslup</code></li>
20+
21+<li><a href="https://github.com/Fang-/urbit-string">String processing</a>
22+<br />
23+<code>~palfun-foslup</code></li>
24+
25+<li><a href="community-projects/nock-implementations">Nock implementations</a>
26+</li>
27+
28+</ul>
29+
30+</div>
docs/community-projects/nock-implementations.mdnew file+10
@@ -0,0 +1,10 @@
1+---
2+navhome: /docs/
3+sort: 4
4+title: Nock implementations
5+next: true
6+---
7+
8+# Community Nock implementations
9+
10+<list src="."></list>
docs/community-projects/nock-implementations/clojure.mdnew file+125
@@ -0,0 +1,125 @@
1+---
2+navhome: /docs/
3+title: Clojure
4+sort: 5
5+next: true
6+---
7+
8+# Clojure
9+
10+From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
11+
12+```
13+(ns anock.core
14+ (:import anock.NockException))
15+
16+(declare atom? cell? cell)
17+
18+(defn noun?
19+ "A noun is an atom or a cell."
20+ [noun & ns]
21+ (if ns false
22+ (or (atom? noun) (cell? noun))))
23+
24+(defn atom?
25+ "An atom is a natural number."
26+ [noun & ns]
27+ (if ns false
28+ (and (integer? noun) (>= noun 0))))
29+
30+(defn cell?
31+ "A cell is an ordered pair of nouns."
32+ [noun]
33+ (cond
34+ (atom? noun) false
35+ (nil? noun) false
36+ (not= 2 (count noun)) false
37+ :else (and (noun? (first noun))
38+ (noun? (second noun)))))
39+
40+(defn tis
41+ "= (pronounced 'tis') tests a cell for equality."
42+ [noun]
43+ (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
44+ (let [[a b] noun]
45+ (if (= a b) 0 1))))
46+
47+(defn wut
48+ "? (pronounced 'wut') tests whether a noun is a cell."
49+ [noun]
50+ (cond
51+ (atom? noun) 1
52+ (cell? noun) 0
53+ :else (throw (anock.NockException. "Invalid noun."))))
54+
55+(defn lus
56+ "+ (pronounced 'lus') adds 1 to an atom."
57+ [noun]
58+ (if (atom? noun) (inc noun)
59+ (throw (anock.NockException. "Can only lus atoms."))))
60+
61+(defn fas
62+ "/ (pronounced 'fas') is a tree address function."
63+ [noun]
64+ (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
65+ (let [[a b] (cell noun)]
66+ (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
67+ (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
68+ (throw (anock.NockException. (str "Cannot fas noun: " noun))))
69+ (cond
70+ (= 1 a) b
71+ (= 2 a) (first b)
72+ (= 3 a) (second b)
73+ (even? a) (fas [2 (fas [(/ a 2) b])])
74+ (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
75+
76+(defn tar
77+ "* (pronounced 'tar') means Nock"
78+ [noun]
79+ (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
80+ (try
81+ (let [noun (cell noun) [x [y z]] noun]
82+ (cond
83+ (cell? y) (cell (tar [x y]) (tar [x z]))
84+ (zero? y) (fas [z x])
85+ (= 1 y) z
86+ (= 3 y) (wut (tar [x z]))
87+ (= 4 y) (lus (tar [x z]))
88+ (= 5 y) (tis (tar [x z]))
89+ :else (let [[p q] z]
90+ (cond
91+ (= 2 y) (tar [(tar [x p]) (tar [x q])])
92+ (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
93+ [1 0] 2 [1 2 3] [1 0] 4 4 p])
94+ (= 7 y) (tar [x 2 p 1 q])
95+ (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
96+ (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
97+ (= 10 y) (if (cell? p)
98+ (tar [x 8 (second p) 7 [0 3] q])
99+ (tar [x q]))))))
100+ (catch RuntimeException e
101+ (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
102+
103+(def nock tar)
104+
105+; Some convenience functions
106+(defn apply* [f x]
107+ (if (and (= 1 (count x)) (coll? (first x)))
108+ (apply f x)
109+ (f x)))
110+
111+(defn bracket
112+ "[a b c] -> [a [b c]]"
113+ [[a & b :as c]]
114+ (let [b (vec b)]
115+ (cond
116+ (and (noun? a) (apply noun? b)) (vec c)
117+ (apply noun? b) (apply vector (bracket a) b)
118+ (noun? a) [a (apply* bracket b)]
119+ :else [(bracket a) (apply* bracket b)])))
120+
121+(defn cell [& nouns]
122+ (if (apply atom? nouns)
123+ (throw (anock.NockException. "Cannot convert atom to cell."))
124+ (apply* bracket nouns)))
125+```
docs/community-projects/nock-implementations/csharp.mdnew file+478
@@ -0,0 +1,478 @@
1+---
2+navhome: /docs/
3+title: C#
4+sort: 12
5+next: true
6+---
7+
8+# C#
9+
10+From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
11+
12+```
13+using System;
14+using System.Collections.Generic;
15+using System.Linq;
16+using System.Text;
17+using System.Text.RegularExpressions;
18+
19+namespace NockInterpreter
20+{
21+ class Interpreter
22+ {
23+ static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
24+
25+ public static Noun Nock(Noun noun)
26+ {
27+ Start:
28+ Noun cache_noun;
29+ if (memocache.TryGetValue(noun.ToString(), out cache_noun))
30+ {
31+ return cache_noun;
32+ }
33+
34+ if (Atom.IsAtom(noun))
35+ throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
36+ else
37+ {
38+ Noun subject = noun.n1;
39+ if (Noun.IsCell(noun.n2))
40+ {
41+ Cell formula = (Cell)noun.n2;
42+ if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
43+ {
44+ Atom op = (Atom)formula.n1;
45+ Noun operands = formula.n2;
46+
47+ switch (op.value)
48+ {
49+ case 0: // 25 :: *[a 0 b] /[b a]
50+ memocache[noun.ToString()] = fas(operands, subject);
51+ return memocache[noun.ToString()];
52+ case 1: // 26 :: *[a 1 b] b
53+ memocache[noun.ToString()] = operands;
54+ return memocache[noun.ToString()];
55+ case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
56+ if (Noun.IsCell(operands))
57+ {
58+ Noun a = Nock(subject, operands.n1);
59+ Noun b = Nock(subject, operands.n2);
60+ noun = Noun.CreateNoun(a, b);
61+ goto Start;
62+ // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
63+ }
64+ throw new Exception("Atom after operand 2: " + operands.ToString());
65+ case 3: // 28 :: *[a 3 b] ?*[a b]
66+ memocache[noun.ToString()] = wut(Nock(subject, operands));
67+ return memocache[noun.ToString()];
68+ case 4: // 29 :: *[a 4 b] +*[a b]
69+ memocache[noun.ToString()] = lus(Nock(subject, operands));
70+ return memocache[noun.ToString()];
71+ case 5: // 30 :: *[a 5 b] =*[a b]
72+ memocache[noun.ToString()] = tis(Nock(subject, operands));
73+ return memocache[noun.ToString()];
74+ case 6: // 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]
75+ if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
76+ {
77+ Noun b = operands.n1;
78+ Noun c = operands.n2.n1;
79+ Noun d = operands.n2.n2;
80+ noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
81+ goto Start;
82+ // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
83+ }
84+ throw new Exception("Unhandled pattern for operand 6");
85+ case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
86+ if (Noun.IsCell(operands))
87+ {
88+ Noun b = operands.n1;
89+ Noun c = operands.n2;
90+ noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
91+ goto Start;
92+ // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
93+ }
94+ throw new Exception("Atom after operand 7: " + operands.ToString());
95+ case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
96+ if (Noun.IsCell(operands))
97+ {
98+ Noun b = operands.n1;
99+ Noun c = operands.n2;
100+ noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
101+ goto Start;
102+ // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
103+ }
104+ throw new Exception("Atom after operand 8: " + operands.ToString());
105+ case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
106+ if (Noun.IsCell(operands))
107+ {
108+ Noun b = operands.n1;
109+ Noun c = operands.n2;
110+ noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
111+ goto Start;
112+ // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
113+ }
114+ throw new Exception("Atom after operand 9: " + operands.ToString());
115+ case 10:
116+ if (Noun.IsCell(operands))
117+ {
118+ if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
119+ {
120+ Noun b = operands.n1.n1;
121+ Noun c = operands.n1.n2;
122+ Noun d = operands.n2;
123+ noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
124+ goto Start;
125+ // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
126+ }
127+ else // 37 :: *[a 10 b c] *[a c]
128+ {
129+ Noun c = operands.n2;
130+ noun = Noun.CreateNoun(subject, c);
131+ goto Start;
132+ // return Nock(subject, c);
133+ }
134+ }
135+ throw new Exception("Atom after operand 10: " + operands.ToString());
136+ default:
137+ throw new Exception("Unknown operand: " + op.value);
138+ }
139+ }
140+ else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
141+ {
142+ memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
143+ return memocache[noun.ToString()];
144+ }
145+ }
146+ }
147+ throw new Exception("Unhandled pattern");
148+ }
149+
150+ public static Noun Nock(string program)
151+ {
152+ Noun noun = Noun.CreateNoun(program);
153+ return Nock(noun);
154+ }
155+
156+ public static Noun Nock(Noun n1, Noun n2)
157+ {
158+ Noun noun = Noun.CreateNoun(n1, n2);
159+ return Nock(noun);
160+ }
161+
162+ private static Noun tis(Noun noun)
163+ {
164+ if (Noun.IsAtom(noun.ToString()))
165+ throw new Exception("Infinite loop tising an atom: " + noun.ToString());
166+ else
167+ {
168+ Cell cell = (Cell)noun;
169+
170+ if (cell.n1.ToString() == cell.n2.ToString())
171+ return Noun.CreateNoun("0");
172+ else
173+ return Noun.CreateNoun("1");
174+ }
175+ }
176+
177+ private static Noun lus(Noun noun)
178+ {
179+ if (Noun.IsAtom(noun.ToString()))
180+ {
181+ Atom a = (Atom)noun;
182+ int v = a.value + 1;
183+ return Noun.CreateNoun(v.ToString());
184+ }
185+ else
186+ throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
187+ }
188+
189+ private static Noun wut(Noun noun)
190+ {
191+ if (Noun.IsAtom(noun.ToString()))
192+ return Noun.CreateNoun("1");
193+ else
194+ return Noun.CreateNoun("0");
195+ }
196+
197+ private static Noun fas(Noun n1, Noun n2)
198+ {
199+ Noun noun = Noun.CreateNoun(n1, n2);
200+ return fas(noun);
201+ }
202+
203+ private static Noun fas(Noun noun)
204+ {
205+ if (Noun.IsAtom(noun.ToString()))
206+ throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
207+ else
208+ {
209+ Cell c = (Cell)noun;
210+ // If n1 isn't an atom, I assume we throw? This isn't defined in the spec. Confirmed by John B by email. This spins forever.
211+ if (Noun.IsCell(c.n1.ToString()))
212+ throw new Exception("Axis must be an atom: " + c.ToString());
213+ else
214+ {
215+ Atom a = (Atom)c.n1;
216+ if (a.value == 1)
217+ return c.n2;
218+ else if (a.value >= 2)
219+ {
220+ if (!Noun.IsCell(c.n2.ToString()))
221+ {
222+ throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
223+ }
224+ else
225+ {
226+ Cell c2 = (Cell)c.n2;
227+ if (a.value == 2)
228+ return c2.n1;
229+ else if (a.value == 3)
230+ return c2.n2;
231+ else if (a.value % 2 == 0)
232+ {
233+ int half = a.value / 2;
234+ return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
235+ }
236+ else if (a.value % 2 == 1)
237+ {
238+ int half = a.value / 2;
239+ return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
240+ }
241+ else
242+ {
243+ throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
244+ }
245+ }
246+ }
247+ }
248+ throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
249+ }
250+ }
251+ }
252+
253+ class Noun
254+ {
255+ public Noun n1;
256+ public Noun n2;
257+
258+ // takes a program, returns a pair of nouns, stringified.
259+ public static Tuple<string, string> SplitCell(string program)
260+ {
261+
262+ int stackCount = 0;
263+ int i = 0;
264+ // split the string right after the first space
265+ foreach (char c in program)
266+ {
267+ if (IsValidChar(c))
268+ {
269+ if (c == '[')
270+ stackCount++;
271+ else if (c == ']')
272+ stackCount--;
273+ else if (c == ' ')
274+ {
275+ // if we see a space, and our stack count is at 1, then we've found our split point
276+ if (stackCount == 1)
277+ {
278+ string a = program.Substring(1, i - 1);
279+ string b = program.Substring(i + 1, program.Length - (i + 2));
280+
281+ // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
282+ if (!IsCell(b) && !IsAtom(b))
283+ b = "[" + b + "]";
284+ Tuple<string, string> tuple = new Tuple<string, string>(a, b);
285+ return tuple;
286+ }
287+ }
288+ }
289+ else
290+ throw new Exception("Invalid char in cell: " + c);
291+ i++;
292+ }
293+ throw new Exception("Invalid cell: " + program);
294+ }
295+
296+ public static bool IsCell(string program)
297+ {
298+ // check if cell is valid, as above but make sure no space after bracket
299+ // valid tokens are: space, int, [, ]
300+ // from [ => [, int
301+ // from int => space, ], int
302+ // from ] => space, ]
303+ // from space => int, [
304+
305+ // stack count must always be nonzero
306+ // first and last elements must be [ and ]
307+
308+ int i = 0; // i is the stack count for brackets.
309+ int counter = 0;
310+ char s = '\0'; // s is the last seen character
311+ // split the string right after the first space
312+ foreach (char c in program)
313+ {
314+ if (s == '\0')
315+ {
316+ if (c != '[')
317+ return false;
318+ }
319+ else if (s == '[')
320+ {
321+ if (!(c == '[' || IsInt(c)))
322+ return false;
323+ }
324+ else if (IsInt(s))
325+ {
326+ if (!(IsInt(c) || c == ' ' || c == ']'))
327+ return false;
328+ }
329+ else if (s == ']')
330+ {
331+ if (!(c == ']' || c == ' '))
332+ return false;
333+ }
334+ else if (s == ' ')
335+ {
336+ if (!(c == '[' || IsInt(c)))
337+ return false;
338+ }
339+ s = c;
340+ counter++;
341+ if (c == '[')
342+ i++;
343+ else if (c == ']')
344+ i--;
345+ if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
346+ return false;
347+ }
348+
349+ // We should end with stack count of zero
350+ if (i == 0)
351+ return true;
352+ else
353+ return false;
354+ }
355+
356+ public static bool IsInt(char c)
357+ {
358+ if (c == '0' ||
359+ c == '1' ||
360+ c == '2' ||
361+ c == '3' ||
362+ c == '4' ||
363+ c == '5' ||
364+ c == '6' ||
365+ c == '7' ||
366+ c == '8' ||
367+ c == '9')
368+ return true;
369+ else
370+ return false;
371+ }
372+
373+ public static bool IsValidChar(char c)
374+ {
375+ if (c == ' ' ||
376+ c == '[' ||
377+ c == ']' ||
378+ IsInt(c))
379+ return true;
380+ else
381+ return false;
382+ }
383+
384+ public static bool IsAtom(string program)
385+ {
386+ int i = 0;
387+ if (int.TryParse(program, out i))
388+ {
389+ if (i >= 0)
390+ return true;
391+ }
392+ return false;
393+ }
394+
395+ public static bool IsAtom(Noun noun)
396+ {
397+ return IsAtom(noun.ToString());
398+ }
399+
400+ public static bool IsCell(Noun noun)
401+ {
402+ return IsCell(noun.ToString());
403+ }
404+
405+ public static Noun CreateNoun(string program)
406+ {
407+ if (IsAtom(program))
408+ return new Atom(program);
409+ else
410+ return new Cell(program);
411+ }
412+
413+ public static Noun CreateNoun(Noun n1, Noun n2)
414+ {
415+ return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
416+ }
417+
418+ public static Noun CreateNoun(string p1, Noun n2)
419+ {
420+ return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
421+ }
422+
423+ public static Noun CreateNoun(Noun n1, string p2)
424+ {
425+ return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
426+ }
427+
428+ public static Noun CreateNoun(string p1, string p2)
429+ {
430+ return CreateNoun("[" + p1 + " " + p2 + "]");
431+ }
432+ }
433+
434+ class Atom : Noun
435+ {
436+ public int value;
437+
438+ public override string ToString()
439+ {
440+ return value.ToString();
441+ }
442+
443+ public Atom(string program)
444+ {
445+ if (IsAtom(program))
446+ {
447+ int i = 0;
448+ bool result = int.TryParse(program, out i);
449+ value = i;
450+ }
451+ else
452+ throw new ArgumentException("Invalid Atom: " + program);
453+ n1 = null;
454+ n2 = null;
455+ }
456+ }
457+
458+ class Cell : Noun
459+ {
460+ public override string ToString()
461+ {
462+ return "[" + n1.ToString() + " " + n2.ToString() + "]";
463+ }
464+
465+ public Cell(string program)
466+ {
467+ if (IsCell(program))
468+ {
469+ Tuple<string, string> split = SplitCell(program);
470+ n1 = CreateNoun(split.Item1);
471+ n2 = CreateNoun(split.Item2);
472+ }
473+ else
474+ throw new ArgumentException("Invalid Cell: " + program);
475+ }
476+ }
477+}
478+```
docs/community-projects/nock-implementations/groovy.mdnew file+206
@@ -0,0 +1,206 @@
1+---
2+navhome: /docs/
3+title: Groovy
4+sort: 7
5+next: true
6+---
7+
8+# Groovy
9+
10+From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
11+
12+```
13+@Memoized
14+def i(def a) {
15+ a.class in [
16+ byte, Byte,
17+ char, Character,
18+ short, Short,
19+ int, Integer,
20+ long, Long,
21+ BigInteger
22+ ] && a >= 0
23+}
24+
25+@Memoized
26+def n(def a) {
27+ def r
28+ n(a, { r = it })
29+ r
30+}
31+
32+@TailRecursive
33+def n(def a, def r) {
34+ if (a in List) {
35+ if (a.size() == 1) {
36+ r(a[0])
37+ } else if (a.size() >= 2) {
38+ n(a[0], { t ->
39+ n(a.size() == 2 ? a[1] : a.tail(), { h ->
40+ r([t, h])
41+ })
42+ })
43+ } else {
44+ throw new IllegalStateException()
45+ }
46+ } else if (i(a)) {
47+ r((BigInteger) a)
48+ } else {
49+ throw new IllegalStateException()
50+ }
51+}
52+
53+@Memoized
54+def wut(def a) {
55+ i(a) ? 1 : 0
56+}
57+
58+@Memoized
59+def lus(def a) {
60+ if (wut(a) == 0) {
61+ throw new IllegalStateException()
62+ }
63+ 1 + a
64+}
65+
66+@Memoized
67+def tis(def a) {
68+ if (wut(a) == 1) {
69+ throw new IllegalStateException()
70+ }
71+ a[0] == a[1] ? 0 : 1
72+}
73+
74+@Memoized
75+def fas(def a) {
76+ def r
77+ fas(a, { r = it })
78+ r
79+}
80+
81+@TailRecursive
82+def fas(def a, def r) {
83+ if (wut(a) == 1) {
84+ throw new IllegalStateException()
85+ }
86+ def h = a[0]
87+ if (!i(h)) {
88+ throw new IllegalStateException()
89+ }
90+ def t = a[1]
91+ if (h == 0) {
92+ throw new IllegalStateException()
93+ } else if (h == 1) {
94+ r(t)
95+ } else {
96+ if (i(t)) {
97+ throw new IllegalStateException()
98+ }
99+ if (h == 2) {
100+ r(t[0])
101+ } else if (h == 3) {
102+ r(t[1])
103+ } else {
104+ fas([h.intdiv(2), t], { p ->
105+ fas([2 + h.mod(2), p], { q ->
106+ r(q)
107+ })
108+ })
109+ }
110+ }
111+}
112+
113+@Memoized
114+def tar(def a) {
115+ def r
116+ tar(a, { r = it})
117+ r
118+}
119+
120+@TailRecursive
121+def tar(def a, def r) {
122+ if (wut(a) == 1) {
123+ throw new IllegalStateException()
124+ }
125+ def s = a[0]
126+ def f = a[1]
127+ if (wut(f) == 1) {
128+ throw new IllegalStateException()
129+ }
130+ def o = f[0]
131+ def v = f[1]
132+ if (wut(o) == 0) {
133+ tar([s, o], { p ->
134+ tar([s, v], { q ->
135+ r([p, q])
136+ })
137+ })
138+ } else {
139+ if (o == 0) {
140+ r(fas([v, s]))
141+ } else if (o == 1) {
142+ r(v)
143+ } else if (o == 3) {
144+ tar([s, v], {
145+ r(wut(it))
146+ })
147+ } else if (o == 4) {
148+ tar([s, v], {
149+ r(lus(it))
150+ })
151+ } else if (o == 5) {
152+ tar([s, v], {
153+ r(tis(it))
154+ })
155+ } else {
156+ if (wut(v) == 1) {
157+ throw new IllegalStateException()
158+ }
159+ def x = v[0]
160+ def y = v[1]
161+ if (o == 2) {
162+ tar([s, x], { p ->
163+ tar([s, y], { q ->
164+ tar([p, q], {
165+ r(it)
166+ })
167+ })
168+ })
169+ } else if (o == 7) {
170+ tar(n([s, 2, x, 1, y]), {
171+ r(it)
172+ })
173+ } else if (o == 8) {
174+ tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
175+ r(it)
176+ })
177+ } else if (o == 9) {
178+ tar(n([s, 7, y, 2, [0, 1], 0, x]), {
179+ r(it)
180+ })
181+ } else if (o == 10) {
182+ if (wut(x) == 1) {
183+ tar([s, y], {
184+ r(it)
185+ })
186+ } else {
187+ tar(n([s, 8, x[1], 7, [0, 3], y]), {
188+ r(it)
189+ })
190+ }
191+ } else {
192+ if (wut(y) == 1) {
193+ throw new IllegalStateException()
194+ }
195+ if (o == 6) {
196+ tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
197+ r(it)
198+ })
199+ } else {
200+ throw new IllegalStateException()
201+ }
202+ }
203+ }
204+ }
205+}
206+```
docs/community-projects/nock-implementations/haskell.mdnew file+63
@@ -0,0 +1,63 @@
1+---
2+navhome: /docs/
3+title: Haskell
4+sort: 3
5+next: true
6+---
7+
8+# Haskell
9+
10+From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
11+
12+```
13+module Language.Nock5K.Spec where
14+import Control.Monad.Instances
15+
16+wut (a :- b) = return $ Atom 0
17+wut a = return $ Atom 1
18+
19+lus (a :- b) = Left "+[a b]"
20+lus (Atom a) = return $ Atom (1 + a)
21+
22+tis (a :- a') | a == a' = return $ Atom 0
23+tis (a :- b) = return $ Atom 1
24+tis a = Left "=a"
25+
26+fas (Atom 1 :- a) = return a
27+fas (Atom 2 :- a :- b) = return a
28+fas (Atom 3 :- a :- b) = return b
29+fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
30+ fas $ Atom (2 + (a `mod` 2)) :- x
31+fas a = Left "/a"
32+
33+tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
34+ y <- tar (a :- d)
35+ return $ x :- y
36+
37+tar (a :- Atom 0 :- b) = fas $ b :- a
38+tar (a :- Atom 1 :- b) = return b
39+tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
40+ y <- tar (a :- c)
41+ tar $ x :- y
42+tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
43+tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
44+tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
45+
46+tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
47+ Atom 2 :- (Atom 1 :- c :- d) :-
48+ (Atom 1 :- Atom 0) :- Atom 2 :-
49+ (Atom 1 :- Atom 2 :- Atom 3) :-
50+ (Atom 1 :- Atom 0) :- Atom 4 :-
51+ Atom 4 :- b)
52+tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
53+tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
54+ ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
55+ Atom 0 :- Atom 1) :- c)
56+tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
57+ (Atom 0 :- Atom 1) :- Atom 0 :- b)
58+tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
59+ (Atom 0 :- Atom 3) :- d)
60+tar (a :- Atom 10 :- b :- c) = tar (a :- c)
61+
62+tar a = Left "*a"
63+```
docs/community-projects/nock-implementations/hoon.mdnew file+54
@@ -0,0 +1,54 @@
1+---
2+navhome: /docs/
3+title: Hoon
4+sort: 11
5+---
6+
7+# Hoon
8+
9+```
10+|= {sub/* fol/*}
11+^- *
12+?< ?=(@ fol)
13+?: ?=(^ -.fol)
14+ [$(fol -.fol) $(fol +.fol)]
15+?+ fol
16+ !!
17+ {$0 b/@}
18+ ?< =(0 b.fol)
19+ ?: =(1 b.fol) sub
20+ ?< ?=(@ sub)
21+ =+ [now=(cap b.fol) lat=(mas b.fol)]
22+ $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
23+::
24+ {$1 b/*}
25+ b.fol
26+::
27+ {$2 b/{^ *}}
28+ =+ ben=$(fol b.fol)
29+ $(sub -.ben, fol +.ben)
30+::
31+ {$3 b/*}
32+ =+ ben=$(fol b.fol)
33+ .?(ben)
34+::
35+ {$4 b/*}
36+ =+ ben=$(fol b.fol)
37+ ?> ?=(@ ben)
38+ +(ben)
39+::
40+ {$5 b/*}
41+ =+ ben=$(fol b.fol)
42+ ?> ?=(^ ben)
43+ =(-.ben +.ben)
44+::
45+ {$6 b/* c/* d/*}
46+ $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
47+::
48+ {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
49+ {$8 b/* c/*} $(fol =>(fol [7 [[0 1] b] c]))
50+ {$9 b/* c/*} $(fol =>(fol [7 c 0 b]))
51+ {$10 @ c/*} $(fol c.fol)
52+ {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
53+==
54+```
docs/community-projects/nock-implementations/javascript.mdnew file+365
@@ -0,0 +1,365 @@
1+---
2+navhome: /docs/
3+title: Javascript
4+sort: 9
5+next: true
6+---
7+
8+# Javascript
9+
10+From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
11+
12+```js
13+(function (self, factory) {
14+ 'use strict'
15+
16+ if (typeof define === 'function' && define.amd) {
17+ define([], factory)
18+ } else if (typeof module === 'object' && typeof module.exports === 'object') {
19+ module.exports = factory()
20+ } else {
21+ self.nock = factory()
22+ }
23+}(this, function () {
24+ 'use strict'
25+
26+ /**
27+ * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
28+ * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
29+ *
30+ * @see http://urbit.org/docs/nock/definition/
31+ * @see http://media.urbit.org/whitepaper.pdf
32+ */
33+
34+ var useMacros = false
35+
36+ /*
37+ * code conventions:
38+ *
39+ * `n` is a noun,
40+ * `s` is a subject noun,
41+ * `f` is a formula (or cell of formulas)
42+ */
43+
44+ /* operators */
45+
46+ /**
47+ * wut (?): test for atom (1) or cell (0)
48+ *
49+ * ?[a b] 0
50+ * ?a 1
51+ */
52+ function wut (n) {
53+ return typeof n === 'number' ? 1 : 0
54+ }
55+
56+ /**
57+ * lus (+): increment an atom
58+ *
59+ * +[a b] +[a b]
60+ * +a 1 + a
61+ */
62+ function lus (n) {
63+ if (wut(n) === 0) throw new Error('lus cell')
64+ return 1 + n
65+ }
66+
67+ /**
68+ * tis (=): test equality
69+ *
70+ * =[a a] 0
71+ * =[a b] 1
72+ * =a =a
73+ */
74+ function tis (n) {
75+ if (wut(n) === 1) throw new Error('tis atom')
76+ return deepEqual(n[0], n[1]) ? 0 : 1
77+ }
78+
79+ /**
80+ * fas (/): resolve a tree address
81+ *
82+ * /[1 a] a
83+ * /[2 a b] a
84+ * /[3 a b] b
85+ * /[(a + a) b] /[2 /[a b]]
86+ * /[(a + a + 1) b] /[3 /[a b]]
87+ * /a /a
88+ */
89+ function fas (addr, n) {
90+ if (n === undefined) throw new Error('invalid fas noun')
91+ if (addr === 0) throw new Error('invalid fas addr: 0')
92+
93+ if (addr === 1) return n
94+ if (addr === 2) return n[0]
95+ if (addr === 3) return n[1]
96+
97+ return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
98+ }
99+
100+ /* formulas */
101+
102+ /**
103+ * slot (0): resolve a tree address
104+ *
105+ * *[a 0 b] /[b a]
106+ */
107+ function slot (s, f) {
108+ var p = fas(f, s)
109+
110+ if (p === undefined) throw new Error('invalid fas addr: ' + f)
111+
112+ return p
113+ }
114+
115+ /**
116+ * constant (1): return the formula regardless of subject
117+ *
118+ * *[a 1 b] b
119+ */
120+ function constant (s, f) {
121+ return f
122+ }
123+
124+ /**
125+ * evaluate (2): evaluate the product of second formula against the product of the first
126+ *
127+ * *[a 2 b c] *[*[a b] *[a c]]
128+ */
129+ function evaluate (s, f) {
130+ return nock(nock(s, f[0]), nock(s, f[1]))
131+ }
132+
133+ /**
134+ * cell (3): test if the product is a cell
135+ *
136+ * *[a 3 b] ?*[a b]
137+ */
138+ function cell (s, f) {
139+ return wut(nock(s, f))
140+ }
141+
142+ /**
143+ * incr (4): increment the product
144+ *
145+ * *[a 4 b] +*[a b]
146+ */
147+ function incr (s, f) {
148+ return lus(nock(s, f))
149+ }
150+
151+ /**
152+ * eq (5): test for equality between nouns in the product
153+ *
154+ * *[a 5 b] =*[a b]
155+ */
156+ function eq (s, f) {
157+ return tis(nock(s, f))
158+ }
159+
160+ /* macro-formulas */
161+
162+ /**
163+ * ife (6): if/then/else
164+ *
165+ * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
166+ */
167+ function macroIfe (s, f) {
168+ return nock(s, [2, [[0, 1], [2, [[1, [f[1][0], f[1][1]]], [[1, 0], [2, [[1, [2, 3]], [[1, 0], [4, [4, f[0]]]]]]]]]]])
169+ }
170+
171+ function ife (s, f) {
172+ var cond = nock(s, f[0])
173+
174+ if (cond === 0) return nock(s, f[1][0])
175+ if (cond === 1) return nock(s, f[1][1])
176+
177+ throw new Error('invalid ife conditional')
178+ }
179+
180+ /**
181+ * compose (7): evaluate formulas composed left-to-right
182+ *
183+ * *[a 7 b c] *[a 2 b 1 c]
184+ */
185+ function macroCompose (s, f) {
186+ return nock(s, [2, [f[0], [1, f[1]]]])
187+ }
188+
189+ function compose (s, f) {
190+ // alternate form:
191+ // return nock(nock(s, f[0]), constant(s, f[1]))
192+ return nock(nock(s, f[0]), f[1])
193+ }
194+
195+ /**
196+ * extend (8): evaluate the second formula against [product of first, subject]
197+ *
198+ * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
199+ */
200+ function macroExtend (s, f) {
201+ return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
202+ }
203+
204+ function extend (s, f) {
205+ // alternate form:
206+ // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
207+ return nock([nock(s, f[0]), s], f[1])
208+ }
209+
210+ /**
211+ * invoke (9): construct a core and evaluate one of it's arms against it
212+ *
213+ * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
214+ */
215+ function macroInvoke (s, f) {
216+ return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
217+ }
218+
219+ function invoke (s, f) {
220+ var prod = nock(s, f[1])
221+ return nock(prod, slot(prod, f[0]))
222+ }
223+
224+ /**
225+ * hint (10): skip first formula, evaluate second
226+ *
227+ * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
228+ * *[a 10 b c] *[a c]
229+ */
230+ function macroHint (s, f) {
231+ if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
232+ return nock(s, f[1])
233+ }
234+
235+ function hint (s, f) {
236+ if (wut(f[0]) === 0) {
237+ if (wut(f[0][1]) === 1) throw new Error('invalid hint')
238+ nock(s, f[0][1])
239+ }
240+ return nock(s, f[1])
241+ }
242+
243+ /* indexed formula functions */
244+ var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
245+ var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
246+
247+ /**
248+ * nock (*)
249+ *
250+ * the nock function
251+ *
252+ * *[a [b c] d] [*[a b c] *[a d]]
253+ * *a *a
254+ */
255+ function nock (s, f) {
256+ if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
257+
258+ var idx = f[0]
259+
260+ if (idx > 10) throw new Error('invalid formula: ' + idx)
261+
262+ if (useMacros) return macroFormulas[idx](s, f[1])
263+
264+ return formulas[idx](s, f[1])
265+ }
266+
267+ /* construct a JS noun (group an array into pairs, associating right) */
268+ function assoc (x) {
269+ if (!x.length) return x
270+
271+ if (x.length === 1) return assoc(x[0])
272+
273+ return [assoc(x[0]), assoc(x.slice(1))]
274+ }
275+
276+ /* deep equality for arrays or primitives */
277+ function deepEqual (a, b) {
278+ if (a === b) return true
279+
280+ if (!(Array.isArray(a) && Array.isArray(b))) return false
281+ if (a.length !== b.length) return false
282+
283+ for (var i = 0; i < a.length; i++) {
284+ if (!deepEqual(a[i], b[i])) return false
285+ }
286+
287+ return true
288+ }
289+
290+ /* parse a hoon-serialized nock formula and construct a JS noun */
291+ function parseNoun (x) {
292+ if (Array.isArray(x)) return assoc(x)
293+
294+ if (typeof x === 'string') {
295+ var str = x.replace(/[\."']/g, '').split(' ').join(',')
296+ return assoc(JSON.parse(str))
297+ }
298+
299+ return x
300+ }
301+
302+ function nockInterface () {
303+ var args = [].slice.call(arguments)
304+ var subject, formula, noun
305+
306+ if (args.length === 1) {
307+ formula = parseNoun(args[0])
308+ } else if (args.length === 2) {
309+ subject = parseNoun(args[0])
310+ formula = parseNoun(args[1])
311+ } else {
312+ noun = assoc(args)
313+ subject = noun[0]
314+ formula = noun[1]
315+ }
316+
317+ if (!formula) throw new Error('formula required')
318+
319+ if (!subject) {
320+ // !=(~)
321+ subject = [1, 0]
322+ }
323+
324+ return nock(subject, formula)
325+ }
326+
327+ return {
328+ nock: nockInterface,
329+ _nock: nock,
330+ useMacros: function (arg) {
331+ useMacros = arg === undefined || arg
332+ return this
333+ },
334+ util: {
335+ assoc: assoc,
336+ parseNoun: parseNoun,
337+ deepEqual: deepEqual
338+ },
339+ operators: {
340+ wut: wut,
341+ lus: lus,
342+ tis: tis,
343+ fas: fas
344+ },
345+ formulas: {
346+ slot: slot,
347+ constant: constant,
348+ evaluate: evaluate,
349+ cell: cell,
350+ incr: incr,
351+ eq: eq,
352+ macroIfe: macroIfe,
353+ ife: ife,
354+ macroCompose: macroCompose,
355+ compose: compose,
356+ macroExtend: macroExtend,
357+ extend: extend,
358+ macroInvoke: macroInvoke,
359+ invoke: invoke,
360+ macroHint: macroHint,
361+ hint: hint
362+ }
363+ }
364+}))
365+```
docs/community-projects/nock-implementations/python.mdnew file+95
@@ -0,0 +1,95 @@
1+---
2+navhome: /docs/
3+title: Python
4+sort: 1
5+next: true
6+---
7+
8+# Python
9+
10+From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
11+
12+```
13+#!/usr/bin/env python3
14+
15+# []
16+def l(*lst):
17+ if len(lst) == 1:
18+ return(lst[0], 0)
19+ if len(lst) == 2:
20+ return lst
21+ else:
22+ return (lst[0], l(*lst[1:]))
23+
24+# *
25+def nock(noun):
26+ return tar(noun)
27+
28+# ?
29+def wut(noun):
30+ if isinstance(noun, int):
31+ return 1
32+ else:
33+ return 0
34+
35+
36+# +
37+def lus(noun):
38+ if isinstance(noun, int):
39+ return 1 + noun
40+ else:
41+ return noun
42+
43+
44+# =
45+def tis(noun):
46+ if noun[0] == noun[1]:
47+ return 0
48+ else:
49+ return 1
50+
51+
52+# /
53+def slot(noun):
54+ if noun[0] == 1:
55+ return noun[1]
56+ elif noun[0] == 2:
57+ return noun[1][0]
58+ elif noun[0] == 3:
59+ return noun[1][1]
60+ elif noun[0] % 2 == 0:
61+ return slot((2, slot((noun[0] // 2, noun[1]))))
62+ elif noun[0] % 2 == 1:
63+ return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
64+
65+
66+def tar(noun):
67+ if isinstance(noun[1][0], int):
68+ if noun[1][0] == 0:
69+ return slot((noun[1][1], noun[0]))
70+ elif noun[1][0] == 1:
71+ return noun[1][1]
72+ elif noun[1][0] == 2:
73+ return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
74+ elif noun[1][0] == 3:
75+ return wut(nock((noun[0], noun[1][1])))
76+ elif noun[1][0] == 4:
77+ return lus(nock((noun[0], noun[1][1])))
78+ elif noun[1][0] == 5:
79+ return tis(nock((noun[0], noun[1][1])))
80+ elif noun[1][0] == 6:
81+ return nock(l(noun[0], 2, (0, 1), 2, l(1, noun[1][1][1][0], noun[1][1][1][1]), (1, 0), 2, l(1, 2, 3), (1, 0), 4, 4, noun[1][1][0]))
82+ elif noun[1][0] == 7:
83+ return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
84+ elif noun[1][0] == 8:
85+ return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
86+ elif noun[1][0] == 9:
87+ return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
88+ elif noun[1][0] == 10:
89+ if isinstance(noun[1][1][0], int):
90+ return nock((noun[0], noun[1][1][1]))
91+ else:
92+ return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
93+ else:
94+ return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
95+```
docs/community-projects/nock-implementations/ruby.mdnew file+139
@@ -0,0 +1,139 @@
1+---
2+navhome: /docs/
3+title: Ruby
4+sort: 2
5+next: true
6+---
7+
8+# Ruby
9+
10+From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
11+
12+```
13+def str_to_tree(str)
14+ arr = []
15+ str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
16+ end
17+end
18+
19+def max_depth(arr)
20+ ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
21+ ret
22+end
23+
24+def pp(arr)
25+ depth = max_depth(arr)
26+ space = 128
27+ 1.up_to(8) do |depth|
28+ space = space / 2
29+ min = 2 ** (depth - 1)
30+ max = (2 ** depth) - 1
31+ min.upto(max) { |axis|
32+ end
33+
34+end
35+
36+def norm(arr)
37+ return arr unless arr.is_a?(Array)
38+ while arr.size > 2
39+ size = arr.size
40+ arr[size - 2] = [ arr[size - 2], arr.pop ]
41+ end
42+ arr = arr.map { |x| norm(x) }
43+end
44+
45+def wut(arr)
46+ arr.is_a?(Array) ? YES : NO
47+end
48+
49+def lus(atom)
50+ raise "not an atom" unless atom.is_a?(Fixnum)
51+ atom + 1
52+end
53+
54+def tis(arr)
55+ raise "not pair" unless arr.is_a?(Array) && arr.size == 2
56+ ( arr[0] == arr[1] ) ? YES : NO
57+end
58+
59+def slot(axis, arr, allow_error = true)
60+ raise "axis on atom" unless arr.is_a?(Array)
61+ return arr if axis == 1
62+ return arr[0] if axis == 2
63+ return arr[1] if axis == 3
64+ return slot(2, slot(axis/2, arr)) if (axis %2) == 0
65+ return slot(3, slot(axis/2, arr))
66+end
67+
68+
69+def nock(arr)
70+ raise "error: nocking an atom" unless arr.is_a?(Array)
71+
72+ oper = slot(4, arr)
73+ a = slot(2, arr)
74+ b = slot(5, arr)
75+
76+ if oper.is_a?(Array)
77+ return [ nock( [ a, [b, c]]), nock( [a, d]) ]
78+ end
79+
80+
81+ case oper
82+ when 0 then
83+ slot(b,a )
84+
85+ when 1 then
86+ b
87+
88+ when 2 then
89+ b_prime = slot(2, b)
90+ c = slot(3,b)
91+ nock( [ nock([a, b_primce]), nock([a, c]) ])
92+
93+ when 3 then
94+ wut(nock([a, b]))
95+
96+ when 4 then
97+ lus(nock([a, b]))
98+
99+ when 5 then
100+ tis(nock([a, b]))
101+
102+ when 6 then
103+ b_prime = slot(2, b)
104+ c = slot(6,b)
105+ d = slot(7,b)
106+ nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
107+
108+ when 7 then
109+ b_prime = slot(2, b)
110+ c = slot(3,b)
111+ nock( norm ([a, 2, b_prime, 1, c]))
112+
113+ when 8 then
114+ b_prime = slot(2, b)
115+ c = slot(3,b)
116+ nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
117+
118+ when 9 then
119+ b_prime = slot(2, b)
120+ c = slot(3,b)
121+ nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
122+
123+ when 10 then
124+ if wut(slot(2,b)) == TRUE
125+ b_prime = slot(4, b)
126+ c = slot(5, b)
127+ d = slot(3, b)
128+ c = slot(3,b)
129+ nock( norm ([a, 8, c, 7, [0, 3], d]))
130+ else
131+ b_prime = slot(2, b)
132+ c = slot(3, b)
133+ nock( norm ([a, 10, [b, c]]))
134+ end
135+ else
136+ raise "error: unknown opcode #{oper.inspect}"
137+ end
138+end
139+```
docs/community-projects/nock-implementations/scala.mdnew file+86
@@ -0,0 +1,86 @@
1+---
2+navhome: /docs/
3+title: Scala
4+sort: 4
5+next: true
6+---
7+
8+# Scala
9+
10+From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
11+
12+```
13+package object nnnock {
14+
15+ sealed trait Noun;
16+ case class Atom( value : Int ) extends Noun;
17+ case class Cell( head : Noun, tail : Noun ) extends Noun;
18+ implicit def toAtom( value : Int ) : Atom = Atom( value );
19+ implicit def toInt( atom : Atom ) : Int = atom.value;
20+
21+ def nock( a : Noun ) : Noun = *(a)
22+
23+ object Cell {
24+ private def apply( nl : List[Noun] ) : Cell = {
25+ nl match {
26+ case a :: b :: Nil => Cell(a, b);
27+ case a :: b :: c :: Nil => Cell(a, Cell(b, c));
28+ case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
29+ }
30+ }
31+ def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
32+ }
33+
34+ def ?( noun : Noun ) : Noun = noun match {
35+ case _ : Cell => 0;
36+ case _ : Atom => 1;
37+ }
38+
39+ @tailrec def plus( noun : Noun ) : Noun = noun match {
40+ case a : Atom => 1 + a;
41+ case c : Cell => plus( c ); //intentional endless spin
42+ }
43+
44+ def heq( noun : Noun ) : Atom = noun match {
45+ case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
46+ case Cell( a : Cell, b : Atom ) => 1;
47+ case Cell( a : Atom, b : Cell ) => 1;
48+ case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
49+ case a : Atom => heq( a ); //intentional endless spin
50+ }
51+
52+ def /( noun : Noun ) : Noun = noun match {
53+ case Cell(Atom(1), a) => a;
54+ case Cell(Atom(2), Cell(a, b)) => a;
55+ case Cell(Atom(3), Cell(a, b)) => b;
56+ case Cell(Atom(value), b ) => {
57+ val a = value / 2;
58+ val num = if ( value % a == 0 ) 2 else 3;
59+ /(Cell(num, /(Cell(a, b))));
60+ }
61+ case a => /( a ); //intentional endless spin
62+ }
63+
64+ def *( noun : Noun ) : Noun = noun match {
65+ case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
66+ case Cell( a, Cell(Atom(value), tail) ) => {
67+ (value, tail) match {
68+ case (0, b) => /( Cell(b, a) );
69+ case (1, b) => b;
70+ case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
71+ case (3, b) => ?( *( Cell(a,b) ) );
72+ case (4, b) => plus( *( Cell(a,b) ) );
73+ case (5, b) => heq( *( Cell(a,b) ) );
74+ case (6, Cell(b, Cell(c, d))) => *( Cell(a,2,Cell(0,1),2,Cell(1,c,d),Cell(1,0),2,Cell(1,2,3),Cell(1,0),4,4,b) ); //wtf?
75+ case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
76+ case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
77+ case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
78+ case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
79+ case (10, Cell(b, c)) => *( Cell(a,c) );
80+ case _ => *( noun ); //intentional endless spin
81+ }
82+ }
83+ case a => *( a ); //intentional endless spin
84+ }
85+}
86+```
docs/community-projects/nock-implementations/scheme.mdnew file+128
@@ -0,0 +1,128 @@
1+---
2+navhome: /docs/
3+title: Scheme
4+sort: 8
5+next: true
6+---
7+
8+# Scheme
9+
10+From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
11+
12+```
13+(import (rnrs (6)))
14+
15+(define (i a) a)
16+
17+(define (n a r)
18+ (cond
19+ ((list? a)
20+ (let ((l (length a)))
21+ (cond
22+ ((equal? l 0) (raise 1))
23+ ((equal? l 1) (r (car a)))
24+ (else
25+ (let ((t (cond
26+ ((equal? l 2) (cadr a))
27+ (else (cdr a)))))
28+ (n (car a)
29+ (lambda (p) (n t
30+ (lambda (q) (r (cons p q)))))))))))
31+ ((fixnum? a) (r a))
32+ (else (raise 2))))
33+
34+(define (wut a)
35+ (cond
36+ ((fixnum? a) 1)
37+ (else 0)))
38+
39+(define (lus a)
40+ (cond
41+ ((equal? (wut a) 0) (raise 3))
42+ (else (+ 1 a))))
43+
44+(define (tis a)
45+ (cond
46+ ((equal? (wut a) 1) (raise 4))
47+ ((equal? (car a) (cdr a)) 0)
48+ (else 1)))
49+
50+(define (fas a r)
51+ (cond
52+ ((equal? (wut a) 1) (raise 5))
53+ (else
54+ (let ((h (car a))
55+ (t (cdr a)))
56+ (cond
57+ ((not (fixnum? h)) (raise 6))
58+ ((equal? h 0) (raise 7))
59+ ((equal? h 1) (r t))
60+ ((fixnum? t) (raise 8))
61+ ((equal? h 2) (r (car t)))
62+ ((equal? h 3) (r (cdr t)))
63+ (else
64+ (fas (cons (div h 2) t)
65+ (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
66+ (lambda (q) (r q)))))))))))
67+
68+(define (tar a r)
69+ (cond
70+ ((equal? (wut a) 1) (raise 9))
71+ (else
72+ (let ((s (car a))
73+ (f (cdr a)))
74+ (cond
75+ ((equal? (wut f) 1) (raise 10))
76+ (else
77+ (let ((o (car f))
78+ (v (cdr f)))
79+ (cond
80+ ((equal? (wut o) 0) (tar (cons s o)
81+ (lambda (p) (tar (cons s v)
82+ (lambda (q) (r (cons p q)))))))
83+ ((equal? o 0) (r (fas (cons v s) i)))
84+ ((equal? o 1) (r v))
85+ ((equal? o 3) (tar (cons s v)
86+ (lambda (p) (r (wut p)))))
87+ ((equal? o 4) (tar (cons s v)
88+ (lambda (p) (r (lus p)))))
89+ ((equal? o 5) (tar (cons s v)
90+ (lambda (p) (r (tis p)))))
91+ ((equal? (wut v) 1) (raise 11))
92+ (else
93+ (let ((x (car v))
94+ (y (cdr v)))
95+ (cond
96+ ((equal? o 2) (tar (cons s x)
97+ (lambda (p) (tar (cons s y)
98+ (lambda (q) (tar (cons p q)
99+ (lambda (u) (r u))))))))
100+ ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
101+ (lambda (p) (r p))))
102+ ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
103+ (lambda (p) (r p))))
104+ ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
105+ (lambda (p) (r p))))
106+ ((equal? o 10) (cond
107+ ((equal? (wut x) 1) (tar (cons s y)
108+ (lambda (p) (r p))))
109+ (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
110+ (lambda (p) (r p))))))
111+ ((equal? (wut y) 1) (raise 12))
112+ ((equal? o 6) (tar (n (list
113+ (list s)
114+ 2
115+ (list 0 1)
116+ 2
117+ (list 1 (list (car y)) (list (cdr y)))
118+ (list 1 0)
119+ 2
120+ (list 1 2 3)
121+ (list 1 0)
122+ 4
123+ 4
124+ (list x))
125+ i)
126+ (lambda (p) (r p))))
127+ (else (raise 13)))))))))))))
128+```
docs/community-projects/nock-implementations/swift.mdnew file+366
@@ -0,0 +1,366 @@
1+---
2+navhome: /docs/
3+title: Swift
4+sort: 10
5+next: true
6+---
7+
8+# Swift
9+
10+```swift
11+import Foundation
12+// 1 :: A noun is an atom or a cell.
13+// 2 :: An atom is a natural number.
14+// 3 :: A cell is an ordered pair of nouns.
15+// 4
16+// 5 :: nock(a) *a
17+// 6 :: [a b c] [a [b c]]
18+// 7
19+// 8 :: ?[a b] 0
20+// 9 :: ?a 1
21+// 10 :: +[a b] +[a b]
22+// 11 :: +a 1 + a
23+// 12 :: =[a a] 0
24+// 13 :: =[a b] 1
25+// 14 :: =a =a
26+// 15
27+// 16 :: /[1 a] a
28+// 17 :: /[2 a b] a
29+// 18 :: /[3 a b] b
30+// 19 :: /[(a + a) b] /[2 /[a b]]
31+// 20 :: /[(a + a + 1) b] /[3 /[a b]]
32+// 21 :: /a /a
33+// 22
34+// 23 :: *[a [b c] d] [*[a b c] *[a d]]
35+// 24
36+// 25 :: *[a 0 b] /[b a]
37+// 26 :: *[a 1 b] b
38+// 27 :: *[a 2 b c] *[*[a b] *[a c]]
39+// 28 :: *[a 3 b] ?*[a b]
40+// 29 :: *[a 4 b] +*[a b]
41+// 30 :: *[a 5 b] =*[a b]
42+// 31
43+// 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]
44+// 33 :: *[a 7 b c] *[a 2 b 1 c]
45+// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
46+// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
47+// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
48+// 37 :: *[a 10 b c] *[a c]
49+// 38
50+// 39 :: *a *a
51+
52+// 1 :: A noun is an atom or a cell.
53+public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
54+{
55+ // 2 :: An atom is a natural number.
56+ public typealias ATOM = UIntMax
57+
58+ case Atom(ATOM)
59+ // 3 :: A cell is an ordered pair of nouns.
60+ case Cell(Noun, Noun)
61+ case Invalid
62+
63+ public static var YES: Noun { return .Atom(0) }
64+ public static var NO: Noun { return .Atom(1) }
65+
66+ public init(_ noun: Noun) { self = noun }
67+
68+ // 6 :: [a b c] [a [b c]]
69+ public init(_ nouns: [Noun]) {
70+ self = .Invalid
71+ if nouns.count > 0 {
72+ var reverse = nouns.reverse().generate()
73+ self = reverse.next()!
74+ while let n = reverse.next() {
75+ self = .Cell(n, self)
76+ }
77+ }
78+ }
79+
80+ // protocol IntegerLiteralConvertible
81+ public typealias IntegerLiteralType = ATOM
82+ public init(integerLiteral value: IntegerLiteralType) {
83+ self = .Atom(value)
84+ }
85+
86+ // protocol ArrayLiteralConvertible
87+ public typealias Element = Noun
88+ public init(arrayLiteral elements: Element...) {
89+ self = Noun(elements)
90+ }
91+
92+ // Array subscript
93+ public subscript(axis: ATOM) -> Noun {
94+ return fas(.Cell(.Atom(axis), self))
95+ }
96+
97+ // protocol Hashable
98+ public var hashValue: Int {
99+ //return self.description.hashValue
100+ switch self {
101+ case let .Atom(a):
102+ return a.hashValue
103+ case let .Cell(a, b):
104+ return (5381 + 31 &* a.hashValue) &+ b.hashValue
105+ default:
106+ abort()
107+ }
108+ }
109+
110+ // protocol CustomStringConvertible
111+ public var description: String {
112+ return describe()
113+ }
114+
115+ private func describe(depth: Int = 0) -> String {
116+ var sub = ""
117+ let next = depth+1
118+ switch self {
119+ case .Invalid:
120+ return "[%INVALID%]"
121+ case let .Atom(atom):
122+ return "\(atom)"
123+ case let .Cell(.Cell(a, b), c):
124+ sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
125+ case let .Cell(a, b):
126+ sub = "\(a.describe(next)) \(b.describe(next))"
127+ }
128+ return depth == 0 ? "[\(sub)]" : sub
129+ }
130+}
131+
132+// protocol Equatable
133+public func == (left: Noun, right: Noun) -> Bool
134+{
135+ switch (left, right) {
136+ case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
137+ case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
138+ case (.Invalid, .Invalid): return true
139+ default: return false
140+ }
141+}
142+
143+public func wut(noun: Noun) -> Noun
144+{
145+ switch noun {
146+ // 8 :: ?[a b] 0
147+ case .Cell:
148+ return Noun.YES
149+ case .Atom:
150+ // 9 :: ?a 1
151+ return Noun.NO
152+ default:
153+ //return wut(noun)
154+ abort()
155+ }
156+}
157+
158+public func lus(noun: Noun) -> Noun
159+{
160+ if case let .Atom(a) = noun {
161+ // 11 :: +a 1 + a
162+ return .Atom(1+a)
163+ }
164+ // 10 :: +[a b] +[a b]
165+ //return lus(noun)
166+ abort()
167+}
168+
169+public func tis(noun: Noun) -> Noun
170+{
171+ if case let .Cell(a, b) = noun {
172+ // 12 :: =[a a] 0
173+ // 13 :: =[a b] 1
174+ return (a == b) ? Noun.YES : Noun.NO
175+ }
176+ // 14 :: =a =a
177+ //return tis(noun)
178+ abort()
179+}
180+
181+public func fas(noun: Noun) -> Noun
182+{
183+ switch noun {
184+ // 16 :: /[1 a] a
185+ case let .Cell(1, a):
186+ return a
187+ // 17 :: /[2 a b] a
188+ case let .Cell(2, .Cell(a, _)):
189+ return a
190+ // 18 :: /[3 a b] b
191+ case let .Cell(3, .Cell(_, b)):
192+ return b
193+ // 19 :: /[(a + a) b] /[2 /[a b]]
194+ // 20 :: /[(a + a + 1) b] /[3 /[a b]]
195+ case let .Cell(.Atom(axis), tree):
196+ let inner = Noun.Atom(axis / 2)
197+ let outer = Noun.Atom(2 + (axis % 2))
198+ return fas(.Cell(outer, fas(.Cell(inner, tree))))
199+ default:
200+ // 21 :: /a /a
201+ //return fas(noun)
202+ abort()
203+ }
204+}
205+
206+public func tar(noun: Noun) -> Noun
207+{
208+ switch noun {
209+ case let .Cell(a, formula):
210+ switch formula {
211+ // 23 :: *[a [b c] d] [*[a b c] *[a d]]
212+ case let .Cell(.Cell(b, c), d):
213+ return .Cell(tar([a, b, c]), tar([a, d]))
214+
215+ // 25 :: *[a 0 b] /[b a]
216+ case let .Cell(0, b):
217+ return fas([b, a])
218+
219+ // 26 :: *[a 1 b] b
220+ case let .Cell(1, b):
221+ return b
222+
223+ // 27 :: *[a 2 b c] *[*[a b] *[a c]]
224+ case let .Cell(2, .Cell(b, c)):
225+ return tar([tar([a, b]), tar([a, c])])
226+
227+ // 28 :: *[a 3 b] ?*[a b]
228+ case let .Cell(3, b):
229+ return wut(tar([a, b]))
230+
231+ // 29 :: *[a 4 b] +*[a b]
232+ case let .Cell(4, b):
233+ return lus(tar([a, b]))
234+
235+ // 30 :: *[a 5 b] =*[a b]
236+ case let .Cell(5, b):
237+ return tis(tar([a, b]))
238+
239+ // 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]
240+ case let .Cell(6, .Cell(b, .Cell(c, d))):
241+ return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
242+
243+ // 33 :: *[a 7 b c] *[a 2 b 1 c]
244+ case let .Cell(7, .Cell(b, c)):
245+ return tar([a, 2, b, 1, c])
246+
247+ // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
248+ case let .Cell(8, .Cell(b, c)):
249+ return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
250+
251+ // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
252+ case let .Cell(9, .Cell(b, c)):
253+ return tar([a, 7, c, 2, [0, 1], 0, b])
254+
255+ // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
256+ case let .Cell(10, .Cell(.Cell(_, c), d)):
257+ return tar([a, 8, c, 7, [0, 3], d])
258+
259+ // 37 :: *[a 10 b c] *[a c]
260+ case let .Cell(10, .Cell(_, c)):
261+ return tar([a, c]);
262+
263+ default:
264+ //return tar(noun)
265+ abort()
266+ }
267+ default:
268+ //return tar(noun)
269+ abort()
270+ }
271+}
272+
273+
274+public var nock_functions = Dictionary<Noun, Noun -> Noun>()
275+
276+public func dao(formula: Noun) -> Noun->Noun
277+{
278+ if let cached = nock_functions[formula] {
279+ return cached
280+ }
281+
282+ let compiler = { () -> Noun -> Noun in
283+ switch formula {
284+ case let .Cell(.Cell(b, c), d): // Distribution
285+ let (p, q) = (dao(.Cell(b, c)), dao(d))
286+ return { a in .Cell(p(a), q(a)) }
287+
288+ case let .Cell(0, b): // Axis
289+ return { a in fas(.Cell(b, a)) }
290+
291+ case let .Cell(1, b): // Just
292+ return { _ in b }
293+
294+ case let .Cell(2, .Cell(b, c)): // Fire
295+ let (f, g) = (dao(b), dao(c))
296+ return { a in dao(g(a))(f(a)) }
297+
298+ case let .Cell(3, b): // Depth
299+ let f = dao(b)
300+ return { a in wut(f(a)) }
301+
302+ case let .Cell(4, b): // Bump
303+ let f = dao(b)
304+ return { a in lus(f(a)) }
305+
306+ case let .Cell(5, b): // Same
307+ let f = dao(b)
308+ return { a in tis(f(a)) }
309+
310+ case let .Cell(6, .Cell(b, .Cell(c, d))): // If
311+ let (p, q, r) = (dao(b), dao(c), dao(d))
312+ return { a in
313+ switch p(a) {
314+ case Noun.self.YES:
315+ return q(a)
316+ case Noun.self.NO:
317+ return r(a)
318+ default:
319+ return tar(.Cell(a, formula))
320+ }
321+ }
322+
323+ case let .Cell(7, .Cell(b, c)): // Compose
324+ let (f, g) = (dao(b), dao(c))
325+ return { a in g(f(a)) }
326+
327+ case let .Cell(8, .Cell(b, c)): // Push
328+ let (f, g) = (dao(b), dao(c))
329+ return { a in g(.Cell(f(a), a)) }
330+
331+ case let .Cell(9, .Cell(b, c)): // Call
332+ let f = dao(c)
333+ return { a in
334+ let core = f(a)
335+ let arm = dao(fas(.Cell(b, core)))
336+ return arm(core)
337+ }
338+
339+ case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
340+ let ignore = dao(c)
341+ let f = dao(d)
342+ return { a in ignore(a); return f(a) }
343+
344+ case let .Cell(10, .Cell(_, c)): // Hint
345+ let f = dao(c)
346+ return { a in f(a) }
347+
348+ default:
349+ return { a in tar(.Cell(a, formula)) }
350+ }
351+ }
352+
353+ let r = compiler()
354+ nock_functions[formula] = r
355+ return r
356+}
357+
358+public func nock(n: Noun) -> Noun
359+{
360+ if case let .Cell(a, b) = n {
361+ let f = dao(b)
362+ return f(a)
363+ }
364+ return nock(n)
365+}
366+```
docs/community-projects/string-processing.mdnew file+17
@@ -0,0 +1,17 @@
1+---
2+navhome: /docs/
3+sort: 3
4+title: A Hoon string processing library
5+next: true
6+---
7+
8+
9+# A Hoon string processing library
10+
11+<div>
12+
13+<h5><a href="https://github.com/Fang-/urbit-string">A Hoon string processing library</a>
14+<br />
15+<code>~palfun-foslup</code></h5>
16+
17+</div>
docs/community-projects/talkbot.mdnew file+17
@@ -0,0 +1,17 @@
1+---
2+navhome: /docs/
3+sort: 2
4+title: ~talkbot: the one and only
5+next: true
6+---
7+
8+
9+# ~talkbot: the one and only
10+
11+<div>
12+
13+<h5><a href="https://github.com/Fang-/talkbot">~talkbot, the one and only</a>
14+<br />
15+<code>~palfun-foslup</code></h5>
16+
17+</div>
docs/community-projects/yint.mdnew file+17
@@ -0,0 +1,17 @@
1+---
2+navhome: /docs/
3+sort: 1
4+title: Yint: A Tiny MUD
5+next: true
6+---
7+
8+
9+# Yint: A TinyMUD Compatible MUD Server
10+
11+<div>
12+
13+<h5><a href="https://github.com/ponnys-podfer/yint">Yint: A TinyMUD Compatible MUD server</a>
14+<br />
15+<code>~ponnys-podfer</code></h5>
16+
17+</div>
docs/hoon/advanced.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 17
3+sort: 16
44next: true
55title: Advanced types
66---
docs/hoon/demo.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 10
3+sort: 11
44next: true
55title: Demo
66---
docs/hoon/examples.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 18
3+sort: 17
44title: Examples
55next: true
66---
docs/hoon/exercises.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 11
3+sort: 18
44title: Exercises
55---
66
docs/hoon/irregular.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 21
3+sort: 22
44title: Irregular forms
55comments: true
66---
docs/hoon/mission.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 12
3+sort: 10
44next: true
55title: Mission
66---
docs/hoon/reference.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 19
3+sort: 21
44title: Twig reference
55---
66
docs/hoon/syntax.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 14
3+sort: 12
44next: true
55title: Syntax
66---
docs/hoon/troubleshooting.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 12
3+sort: 19
44title: Troubleshooting
55next: true
66---
docs/hoon/twig.md+1−1
@@ -1,6 +1,6 @@
11---
22navhome: /docs/
3−sort: 16
3+sort: 14
44next: true
55title: Expressions
66---
docs/nock.md−2
@@ -8,6 +8,4 @@ title: Nock
88
99Nock is our nano-VM. If you're into combinators or want to understand the foundation of Urbit, dive in.
1010
11−Building a Nock interpreter is a fun exercise, as you can see in the [implementations](nock/implementations)
12−
1311<list/>
docs/nock/implementations.md+209−4
@@ -1,9 +1,214 @@
11---
22navhome: /docs/
3−sort: 4
4−title: Implementations
3+title: Implementation
4+sort: 6
5+next: true
56---
67
7−# Implementations
8+# C implementation
89
9−<list src="."></list>
10+The actual production Nock interpreter. Note gotos for tail-call elimination,
11+and manual reference counting. More about the C environment can be found
12+in the [runtime system documentation](../../../runtime).
13+
14+```
15+/* nock(): produce .*(bus fol). Do not virtualize.
16+*/
17+static u3_noun
18+nock(u3_noun bus, u3_noun fol)
19+{
20+ u3_noun hib, gal;
21+
22+ while ( 1 ) {
23+ hib = u3h(fol);
24+ gal = u3t(fol);
25+
26+ if ( c3y == u3r_du(hib) ) {
27+ u3_noun poz, riv;
28+
29+ poz = nock(u3k(bus), u3k(hib));
30+ riv = nock(bus, u3k(gal));
31+
32+ u3a_lose(fol);
33+ return u3i_cell(poz, riv);
34+ }
35+ else switch ( hib ) {
36+ default: return u3m_bail(c3__exit);
37+
38+ case 0: {
39+ if ( c3n == u3r_ud(gal) ) {
40+ return u3m_bail(c3__exit);
41+ }
42+ else {
43+ u3_noun pro = u3k(u3at(gal, bus));
44+
45+ u3a_lose(bus); u3a_lose(fol);
46+ return pro;
47+ }
48+ }
49+ c3_assert(!"not reached");
50+
51+ case 1: {
52+ u3_noun pro = u3k(gal);
53+
54+ u3a_lose(bus); u3a_lose(fol);
55+ return pro;
56+ }
57+ c3_assert(!"not reached");
58+
59+ case 2: {
60+ u3_noun nex = nock(u3k(bus), u3k(u3t(gal)));
61+ u3_noun seb = nock(bus, u3k(u3h(gal)));
62+
63+ u3a_lose(fol);
64+ bus = seb;
65+ fol = nex;
66+ continue;
67+ }
68+ c3_assert(!"not reached");
69+
70+ case 3: {
71+ u3_noun gof, pro;
72+
73+ gof = nock(bus, u3k(gal));
74+ pro = u3r_du(gof);
75+
76+ u3a_lose(gof); u3a_lose(fol);
77+ return pro;
78+ }
79+ c3_assert(!"not reached");
80+
81+ case 4: {
82+ u3_noun gof, pro;
83+
84+ gof = nock(bus, u3k(gal));
85+ pro = u3i_vint(gof);
86+
87+ u3a_lose(fol);
88+ return pro;
89+ }
90+ c3_assert(!"not reached");
91+
92+ case 5: {
93+ u3_noun wim = nock(bus, u3k(gal));
94+ u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
95+
96+ u3a_lose(wim); u3a_lose(fol);
97+ return pro;
98+ }
99+ c3_assert(!"not reached");
100+
101+ case 6: {
102+ u3_noun b_gal, c_gal, d_gal;
103+
104+ u3x_trel(gal, &b_gal, &c_gal, &d_gal);
105+ {
106+ u3_noun tys = nock(u3k(bus), u3k(b_gal));
107+ u3_noun nex;
108+
109+ if ( 0 == tys ) {
110+ nex = u3k(c_gal);
111+ } else if ( 1 == tys ) {
112+ nex = u3k(d_gal);
113+ } else return u3m_bail(c3__exit);
114+
115+ u3a_lose(fol);
116+ fol = nex;
117+ continue;
118+ }
119+ }
120+ c3_assert(!"not reached");
121+
122+ case 7: {
123+ u3_noun b_gal, c_gal;
124+
125+ u3x_cell(gal, &b_gal, &c_gal);
126+ {
127+ u3_noun bod = nock(bus, u3k(b_gal));
128+ u3_noun nex = u3k(c_gal);
129+
130+ u3a_lose(fol);
131+ bus = bod;
132+ fol = nex;
133+ continue;
134+ }
135+ }
136+ c3_assert(!"not reached");
137+
138+ case 8: {
139+ u3_noun b_gal, c_gal;
140+
141+ u3x_cell(gal, &b_gal, &c_gal);
142+ {
143+ u3_noun heb = nock(u3k(bus), u3k(b_gal));
144+ u3_noun bod = u3nc(heb, bus);
145+ u3_noun nex = u3k(c_gal);
146+
147+ u3a_lose(fol);
148+ bus = bod;
149+ fol = nex;
150+ continue;
151+ }
152+ }
153+ c3_assert(!"not reached");
154+
155+ case 9: {
156+ u3_noun b_gal, c_gal;
157+
158+ u3x_cell(gal, &b_gal, &c_gal);
159+ {
160+ u3_noun seb = nock(bus, u3k(c_gal));
161+
162+ if ( c3n == u3r_ud(b_gal) ) {
163+ return u3m_bail(c3__exit);
164+ }
165+ else {
166+ u3_noun nex = u3k(u3at(b_gal, seb));
167+
168+ u3a_lose(fol);
169+ bus = seb;
170+ fol = nex;
171+ continue;
172+ }
173+ }
174+ }
175+ c3_assert(!"not reached");
176+
177+ case 10: {
178+ u3_noun p_gal, q_gal;
179+
180+ u3x_cell(gal, &p_gal, &q_gal);
181+ {
182+ u3_noun zep, hod, nex;
183+
184+ if ( c3y == u3r_du(p_gal) ) {
185+ u3_noun b_gal = u3h(p_gal);
186+ u3_noun c_gal = u3t(p_gal);
187+ u3_noun d_gal = q_gal;
188+
189+ zep = u3k(b_gal);
190+ hod = nock(u3k(bus), u3k(c_gal));
191+ nex = u3k(d_gal);
192+ }
193+ else {
194+ u3_noun b_gal = p_gal;
195+ u3_noun c_gal = q_gal;
196+
197+ zep = u3k(b_gal);
198+ hod = u3_nul;
199+ nex = u3k(c_gal);
200+ }
201+
202+ u3a_lose(zep);
203+ u3a_lose(hod);
204+
205+ return nock(bus, nex);
206+ }
207+ }
208+ c3_assert(!"not reached");
209+ }
210+ }
211+}
212+```
213+
214+Building a Nock interpreter in another language is a fun exercise. Check out our community Nock implementations [here](../../community-projects/nock-implementations)!