on e993912 help sign in
urbit.org/tutorials/nock/implementations.md
2323 lines 65 kB history raw
1+++
2title = "Implementations"
3weight = 4
4template = "doc.html"
5insert_anchor_links = "right"
6+++
8We use a C implementation for our Nock interpreter. But building a Nock interpreter in another language is a fun exercise. Check out our community Nock implementations, shown below our official C implementation. (Note: the community implementations were written for a slightly older version of Nock, Nock 5K. The current version is Nock 4K.):
10## Table of Contents
12- [C](#C)
14- [Clojure](#clojure)
16- [C#](#c-sharp)
18- [Groovy](#groovy)
20- [Haskell](#haskell)
22- [JavaScript](#javascript)
24- [Python](#python)
26- [Ruby](#ruby)
28- [Scala](#scala)
30- [Scheme](#scheme)
32- [Swift](#swift)
34## C Implementation
36The actual production Nock interpreter. Note gotos for tail-call elimination,
37and manual reference counting. More about the C environment can be found
38in the [runtime system documentation](@/docs/tutorials/vere/runtime.md).
39```
40/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
41*/
42static u3_noun
43_n_nock_on(u3_noun bus, u3_noun fol)
45 u3_noun hib, gal;
47 while ( 1 ) {
48 hib = u3h(fol);
49 gal = u3t(fol);
51#ifdef U3_CPU_DEBUG
52 u3R->pro.nox_d += 1;
53#endif
55 if ( c3y == u3r_du(hib) ) {
56 u3_noun poz, riv;
58 poz = _n_nock_on(u3k(bus), u3k(hib));
59 riv = _n_nock_on(bus, u3k(gal));
61 u3a_lose(fol);
62 return u3i_cell(poz, riv);
63 }
64 else switch ( hib ) {
65 default: return u3m_bail(c3__exit);
67 case 0: {
68 if ( c3n == u3r_ud(gal) ) {
69 return u3m_bail(c3__exit);
70 }
71 else {
72 u3_noun pro = u3k(u3at(gal, bus));
74 u3a_lose(bus); u3a_lose(fol);
75 return pro;
76 }
77 }
78 c3_assert(!"not reached");
80 case 1: {
81 u3_noun pro = u3k(gal);
83 u3a_lose(bus); u3a_lose(fol);
84 return pro;
85 }
86 c3_assert(!"not reached");
88 case 2: {
89 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
90 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
92 u3a_lose(fol);
93 bus = seb;
94 fol = nex;
95 continue;
96 }
97 c3_assert(!"not reached");
99 case 3: {
100 u3_noun gof, pro;
102 gof = _n_nock_on(bus, u3k(gal));
103 pro = u3r_du(gof);
105 u3a_lose(gof); u3a_lose(fol);
106 return pro;
107 }
108 c3_assert(!"not reached");
110 case 4: {
111 u3_noun gof, pro;
113 gof = _n_nock_on(bus, u3k(gal));
114 pro = u3i_vint(gof);
116 u3a_lose(fol);
117 return pro;
118 }
119 c3_assert(!"not reached");
121 case 5: {
122 u3_noun wim = _n_nock_on(bus, u3k(gal));
123 u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
125 u3a_lose(wim); u3a_lose(fol);
126 return pro;
127 }
128 c3_assert(!"not reached");
130 case 6: {
131 u3_noun b_gal, c_gal, d_gal;
133 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
134 {
135 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
136 u3_noun nex;
138 if ( 0 == tys ) {
139 nex = u3k(c_gal);
140 } else if ( 1 == tys ) {
141 nex = u3k(d_gal);
142 } else return u3m_bail(c3__exit);
144 u3a_lose(fol);
145 fol = nex;
146 continue;
147 }
148 }
149 c3_assert(!"not reached");
151 case 7: {
152 u3_noun b_gal, c_gal;
154 u3x_cell(gal, &b_gal, &c_gal);
155 {
156 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
157 u3_noun nex = u3k(c_gal);
159 u3a_lose(fol);
160 bus = bod;
161 fol = nex;
162 continue;
163 }
164 }
165 c3_assert(!"not reached");
167 case 8: {
168 u3_noun b_gal, c_gal;
170 u3x_cell(gal, &b_gal, &c_gal);
171 {
172 u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
173 u3_noun bod = u3nc(heb, bus);
174 u3_noun nex = u3k(c_gal);
176 u3a_lose(fol);
177 bus = bod;
178 fol = nex;
179 continue;
180 }
181 }
182 c3_assert(!"not reached");
184 case 9: {
185 u3_noun b_gal, c_gal;
187 u3x_cell(gal, &b_gal, &c_gal);
188 {
189 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
190 u3_noun pro;
192 u3t_off(noc_o);
193 pro = u3j_kick(seb, b_gal);
194 u3t_on(noc_o);
196 if ( u3_none != pro ) {
197 u3a_lose(fol);
198 return pro;
199 }
200 else {
201 if ( c3n == u3r_ud(b_gal) ) {
202 return u3m_bail(c3__exit);
203 }
204 else {
205 u3_noun nex = u3k(u3at(b_gal, seb));
207 u3a_lose(fol);
208 bus = seb;
209 fol = nex;
210 continue;
211 }
212 }
213 }
214 }
215 c3_assert(!"not reached");
217 case 10: {
218 u3_noun p_gal, q_gal;
220 u3x_cell(gal, &p_gal, &q_gal);
221 {
222 u3_noun zep, hod, nex;
224 if ( c3y == u3r_du(p_gal) ) {
225 u3_noun b_gal = u3h(p_gal);
226 u3_noun c_gal = u3t(p_gal);
227 u3_noun d_gal = q_gal;
229 zep = u3k(b_gal);
230 hod = _n_nock_on(u3k(bus), u3k(c_gal));
231 nex = u3k(d_gal);
232 }
233 else {
234 u3_noun b_gal = p_gal;
235 u3_noun c_gal = q_gal;
237 zep = u3k(b_gal);
238 hod = u3_nul;
239 nex = u3k(c_gal);
240 }
242 u3a_lose(fol);
243 return _n_hint(zep, hod, bus, nex);
244 }
245 }
247 case 11: {
248 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
249 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
250 u3_noun val;
252 u3t_off(noc_o);
253 val = u3m_soft_esc(ref, u3k(gof));
254 u3t_on(noc_o);
256 if ( !_(u3du(val)) ) {
257 u3m_bail(u3nt(1, gof, 0));
258 }
259 if ( !_(u3du(u3t(val))) ) {
260 //
261 // replace with proper error stack push
262 //
263 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
264 return u3m_bail(c3__exit);
265 }
266 else {
267 u3_noun pro;
269 u3z(gof);
270 u3z(fol);
271 pro = u3k(u3t(u3t(val)));
272 u3z(val);
274 return pro;
275 }
276 }
277 c3_assert(!"not reached");
278 }
279 }
281```
283## Clojure
285From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
287```
288(ns anock.core
289 (:import anock.NockException))
291(declare atom? cell? cell)
293(defn noun?
294 "A noun is an atom or a cell."
295 [noun & ns]
296 (if ns false
297 (or (atom? noun) (cell? noun))))
299(defn atom?
300 "An atom is a natural number."
301 [noun & ns]
302 (if ns false
303 (and (integer? noun) (>= noun 0))))
305(defn cell?
306 "A cell is an ordered pair of nouns."
307 [noun]
308 (cond
309 (atom? noun) false
310 (nil? noun) false
311 (not= 2 (count noun)) false
312 :else (and (noun? (first noun))
313 (noun? (second noun)))))
315(defn tis
316 "= (pronounced 'tis') tests a cell for equality."
317 [noun]
318 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
319 (let [[a b] noun]
320 (if (= a b) 0 1))))
322(defn wut
323 "? (pronounced 'wut') tests whether a noun is a cell."
324 [noun]
325 (cond
326 (atom? noun) 1
327 (cell? noun) 0
328 :else (throw (anock.NockException. "Invalid noun."))))
330(defn lus
331 "+ (pronounced 'lus') adds 1 to an atom."
332 [noun]
333 (if (atom? noun) (inc noun)
334 (throw (anock.NockException. "Can only lus atoms."))))
336(defn fas
337 "/ (pronounced 'fas') is a tree address function."
338 [noun]
339 (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
340 (let [[a b] (cell noun)]
341 (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
342 (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
343 (throw (anock.NockException. (str "Cannot fas noun: " noun))))
344 (cond
345 (= 1 a) b
346 (= 2 a) (first b)
347 (= 3 a) (second b)
348 (even? a) (fas [2 (fas [(/ a 2) b])])
349 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
351(defn tar
352 "* (pronounced 'tar') means Nock"
353 [noun]
354 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
355 (try
356 (let [noun (cell noun) [x [y z]] noun]
357 (cond
358 (cell? y) (cell (tar [x y]) (tar [x z]))
359 (zero? y) (fas [z x])
360 (= 1 y) z
361 (= 3 y) (wut (tar [x z]))
362 (= 4 y) (lus (tar [x z]))
363 (= 5 y) (tis (tar [x z]))
364 :else (let [[p q] z]
365 (cond
366 (= 2 y) (tar [(tar [x p]) (tar [x q])])
367 (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
368 [1 0] 2 [1 2 3] [1 0] 4 4 p])
369 (= 7 y) (tar [x 2 p 1 q])
370 (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
371 (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
372 (= 10 y) (if (cell? p)
373 (tar [x 8 (second p) 7 [0 3] q])
374 (tar [x q]))))))
375 (catch RuntimeException e
376 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
378(def nock tar)
380; Some convenience functions
381(defn apply* [f x]
382 (if (and (= 1 (count x)) (coll? (first x)))
383 (apply f x)
384 (f x)))
386(defn bracket
387 "[a b c] -> [a [b c]]"
388 [[a & b :as c]]
389 (let [b (vec b)]
390 (cond
391 (and (noun? a) (apply noun? b)) (vec c)
392 (apply noun? b) (apply vector (bracket a) b)
393 (noun? a) [a (apply* bracket b)]
394 :else [(bracket a) (apply* bracket b)])))
396(defn cell [& nouns]
397 (if (apply atom? nouns)
398 (throw (anock.NockException. "Cannot convert atom to cell."))
399 (apply* bracket nouns)))
400```
402## C#
404From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
406```
407using System;
408using System.Collections.Generic;
409using System.Linq;
410using System.Text;
411using System.Text.RegularExpressions;
413namespace NockInterpreter
415 class Interpreter
416 {
417 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
419 public static Noun Nock(Noun noun)
420 {
421 Start:
422 Noun cache_noun;
423 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
424 {
425 return cache_noun;
426 }
428 if (Atom.IsAtom(noun))
429 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
430 else
431 {
432 Noun subject = noun.n1;
433 if (Noun.IsCell(noun.n2))
434 {
435 Cell formula = (Cell)noun.n2;
436 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
437 {
438 Atom op = (Atom)formula.n1;
439 Noun operands = formula.n2;
441 switch (op.value)
442 {
443 case 0: // 25 :: *[a 0 b] /[b a]
444 memocache[noun.ToString()] = fas(operands, subject);
445 return memocache[noun.ToString()];
446 case 1: // 26 :: *[a 1 b] b
447 memocache[noun.ToString()] = operands;
448 return memocache[noun.ToString()];
449 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
450 if (Noun.IsCell(operands))
451 {
452 Noun a = Nock(subject, operands.n1);
453 Noun b = Nock(subject, operands.n2);
454 noun = Noun.CreateNoun(a, b);
455 goto Start;
456 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
457 }
458 throw new Exception("Atom after operand 2: " + operands.ToString());
459 case 3: // 28 :: *[a 3 b] ?*[a b]
460 memocache[noun.ToString()] = wut(Nock(subject, operands));
461 return memocache[noun.ToString()];
462 case 4: // 29 :: *[a 4 b] +*[a b]
463 memocache[noun.ToString()] = lus(Nock(subject, operands));
464 return memocache[noun.ToString()];
465 case 5: // 30 :: *[a 5 b] =*[a b]
466 memocache[noun.ToString()] = tis(Nock(subject, operands));
467 return memocache[noun.ToString()];
468 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]
469 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
470 {
471 Noun b = operands.n1;
472 Noun c = operands.n2.n1;
473 Noun d = operands.n2.n2;
474 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
475 goto Start;
476 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
477 }
478 throw new Exception("Unhandled pattern for operand 6");
479 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
480 if (Noun.IsCell(operands))
481 {
482 Noun b = operands.n1;
483 Noun c = operands.n2;
484 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
485 goto Start;
486 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
487 }
488 throw new Exception("Atom after operand 7: " + operands.ToString());
489 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
490 if (Noun.IsCell(operands))
491 {
492 Noun b = operands.n1;
493 Noun c = operands.n2;
494 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
495 goto Start;
496 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
497 }
498 throw new Exception("Atom after operand 8: " + operands.ToString());
499 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
500 if (Noun.IsCell(operands))
501 {
502 Noun b = operands.n1;
503 Noun c = operands.n2;
504 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
505 goto Start;
506 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
507 }
508 throw new Exception("Atom after operand 9: " + operands.ToString());
509 case 10:
510 if (Noun.IsCell(operands))
511 {
512 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
513 {
514 Noun b = operands.n1.n1;
515 Noun c = operands.n1.n2;
516 Noun d = operands.n2;
517 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
518 goto Start;
519 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
520 }
521 else // 37 :: *[a 10 b c] *[a c]
522 {
523 Noun c = operands.n2;
524 noun = Noun.CreateNoun(subject, c);
525 goto Start;
526 // return Nock(subject, c);
527 }
528 }
529 throw new Exception("Atom after operand 10: " + operands.ToString());
530 default:
531 throw new Exception("Unknown operand: " + op.value);
532 }
533 }
534 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
535 {
536 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
537 return memocache[noun.ToString()];
538 }
539 }
540 }
541 throw new Exception("Unhandled pattern");
542 }
544 public static Noun Nock(string program)
545 {
546 Noun noun = Noun.CreateNoun(program);
547 return Nock(noun);
548 }
550 public static Noun Nock(Noun n1, Noun n2)
551 {
552 Noun noun = Noun.CreateNoun(n1, n2);
553 return Nock(noun);
554 }
556 private static Noun tis(Noun noun)
557 {
558 if (Noun.IsAtom(noun.ToString()))
559 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
560 else
561 {
562 Cell cell = (Cell)noun;
564 if (cell.n1.ToString() == cell.n2.ToString())
565 return Noun.CreateNoun("0");
566 else
567 return Noun.CreateNoun("1");
568 }
569 }
571 private static Noun lus(Noun noun)
572 {
573 if (Noun.IsAtom(noun.ToString()))
574 {
575 Atom a = (Atom)noun;
576 int v = a.value + 1;
577 return Noun.CreateNoun(v.ToString());
578 }
579 else
580 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
581 }
583 private static Noun wut(Noun noun)
584 {
585 if (Noun.IsAtom(noun.ToString()))
586 return Noun.CreateNoun("1");
587 else
588 return Noun.CreateNoun("0");
589 }
591 private static Noun fas(Noun n1, Noun n2)
592 {
593 Noun noun = Noun.CreateNoun(n1, n2);
594 return fas(noun);
595 }
597 private static Noun fas(Noun noun)
598 {
599 if (Noun.IsAtom(noun.ToString()))
600 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
601 else
602 {
603 Cell c = (Cell)noun;
604 // 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.
605 if (Noun.IsCell(c.n1.ToString()))
606 throw new Exception("Axis must be an atom: " + c.ToString());
607 else
608 {
609 Atom a = (Atom)c.n1;
610 if (a.value == 1)
611 return c.n2;
612 else if (a.value >= 2)
613 {
614 if (!Noun.IsCell(c.n2.ToString()))
615 {
616 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
617 }
618 else
619 {
620 Cell c2 = (Cell)c.n2;
621 if (a.value == 2)
622 return c2.n1;
623 else if (a.value == 3)
624 return c2.n2;
625 else if (a.value % 2 == 0)
626 {
627 int half = a.value / 2;
628 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
629 }
630 else if (a.value % 2 == 1)
631 {
632 int half = a.value / 2;
633 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
634 }
635 else
636 {
637 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
638 }
639 }
640 }
641 }
642 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
643 }
644 }
645 }
647 class Noun
648 {
649 public Noun n1;
650 public Noun n2;
652 // takes a program, returns a pair of nouns, stringified.
653 public static Tuple<string, string> SplitCell(string program)
654 {
656 int stackCount = 0;
657 int i = 0;
658 // split the string right after the first space
659 foreach (char c in program)
660 {
661 if (IsValidChar(c))
662 {
663 if (c == '[')
664 stackCount++;
665 else if (c == ']')
666 stackCount--;
667 else if (c == ' ')
668 {
669 // if we see a space, and our stack count is at 1, then we've found our split point
670 if (stackCount == 1)
671 {
672 string a = program.Substring(1, i - 1);
673 string b = program.Substring(i + 1, program.Length - (i + 2));
675 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
676 if (!IsCell(b) && !IsAtom(b))
677 b = "[" + b + "]";
678 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
679 return tuple;
680 }
681 }
682 }
683 else
684 throw new Exception("Invalid char in cell: " + c);
685 i++;
686 }
687 throw new Exception("Invalid cell: " + program);
688 }
690 public static bool IsCell(string program)
691 {
692 // check if cell is valid, as above but make sure no space after bracket
693 // valid tokens are: space, int, [, ]
694 // from [ => [, int
695 // from int => space, ], int
696 // from ] => space, ]
697 // from space => int, [
699 // stack count must always be nonzero
700 // first and last elements must be [ and ]
702 int i = 0; // i is the stack count for brackets.
703 int counter = 0;
704 char s = '\0'; // s is the last seen character
705 // split the string right after the first space
706 foreach (char c in program)
707 {
708 if (s == '\0')
709 {
710 if (c != '[')
711 return false;
712 }
713 else if (s == '[')
714 {
715 if (!(c == '[' || IsInt(c)))
716 return false;
717 }
718 else if (IsInt(s))
719 {
720 if (!(IsInt(c) || c == ' ' || c == ']'))
721 return false;
722 }
723 else if (s == ']')
724 {
725 if (!(c == ']' || c == ' '))
726 return false;
727 }
728 else if (s == ' ')
729 {
730 if (!(c == '[' || IsInt(c)))
731 return false;
732 }
733 s = c;
734 counter++;
735 if (c == '[')
736 i++;
737 else if (c == ']')
738 i--;
739 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
740 return false;
741 }
743 // We should end with stack count of zero
744 if (i == 0)
745 return true;
746 else
747 return false;
748 }
750 public static bool IsInt(char c)
751 {
752 if (c == '0' ||
753 c == '1' ||
754 c == '2' ||
755 c == '3' ||
756 c == '4' ||
757 c == '5' ||
758 c == '6' ||
759 c == '7' ||
760 c == '8' ||
761 c == '9')
762 return true;
763 else
764 return false;
765 }
767 public static bool IsValidChar(char c)
768 {
769 if (c == ' ' ||
770 c == '[' ||
771 c == ']' ||
772 IsInt(c))
773 return true;
774 else
775 return false;
776 }
778 public static bool IsAtom(string program)
779 {
780 int i = 0;
781 if (int.TryParse(program, out i))
782 {
783 if (i >= 0)
784 return true;
785 }
786 return false;
787 }
789 public static bool IsAtom(Noun noun)
790 {
791 return IsAtom(noun.ToString());
792 }
794 public static bool IsCell(Noun noun)
795 {
796 return IsCell(noun.ToString());
797 }
799 public static Noun CreateNoun(string program)
800 {
801 if (IsAtom(program))
802 return new Atom(program);
803 else
804 return new Cell(program);
805 }
807 public static Noun CreateNoun(Noun n1, Noun n2)
808 {
809 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
810 }
812 public static Noun CreateNoun(string p1, Noun n2)
813 {
814 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
815 }
817 public static Noun CreateNoun(Noun n1, string p2)
818 {
819 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
820 }
822 public static Noun CreateNoun(string p1, string p2)
823 {
824 return CreateNoun("[" + p1 + " " + p2 + "]");
825 }
826 }
828 class Atom : Noun
829 {
830 public int value;
832 public override string ToString()
833 {
834 return value.ToString();
835 }
837 public Atom(string program)
838 {
839 if (IsAtom(program))
840 {
841 int i = 0;
842 bool result = int.TryParse(program, out i);
843 value = i;
844 }
845 else
846 throw new ArgumentException("Invalid Atom: " + program);
847 n1 = null;
848 n2 = null;
849 }
850 }
852 class Cell : Noun
853 {
854 public override string ToString()
855 {
856 return "[" + n1.ToString() + " " + n2.ToString() + "]";
857 }
859 public Cell(string program)
860 {
861 if (IsCell(program))
862 {
863 Tuple<string, string> split = SplitCell(program);
864 n1 = CreateNoun(split.Item1);
865 n2 = CreateNoun(split.Item2);
866 }
867 else
868 throw new ArgumentException("Invalid Cell: " + program);
869 }
870 }
872```
874## Groovy
876From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
878```
879@Memoized
880def i(def a) {
881 a.class in [
882 byte, Byte,
883 char, Character,
884 short, Short,
885 int, Integer,
886 long, Long,
887 BigInteger
888 ] && a >= 0
891@Memoized
892def n(def a) {
893 def r
894 n(a, { r = it })
895 r
898@TailRecursive
899def n(def a, def r) {
900 if (a in List) {
901 if (a.size() == 1) {
902 r(a[0])
903 } else if (a.size() >= 2) {
904 n(a[0], { t ->
905 n(a.size() == 2 ? a[1] : a.tail(), { h ->
906 r([t, h])
907 })
908 })
909 } else {
910 throw new IllegalStateException()
911 }
912 } else if (i(a)) {
913 r((BigInteger) a)
914 } else {
915 throw new IllegalStateException()
916 }
919@Memoized
920def wut(def a) {
921 i(a) ? 1 : 0
924@Memoized
925def lus(def a) {
926 if (wut(a) == 0) {
927 throw new IllegalStateException()
928 }
929 1 + a
932@Memoized
933def tis(def a) {
934 if (wut(a) == 1) {
935 throw new IllegalStateException()
936 }
937 a[0] == a[1] ? 0 : 1
940@Memoized
941def fas(def a) {
942 def r
943 fas(a, { r = it })
944 r
947@TailRecursive
948def fas(def a, def r) {
949 if (wut(a) == 1) {
950 throw new IllegalStateException()
951 }
952 def h = a[0]
953 if (!i(h)) {
954 throw new IllegalStateException()
955 }
956 def t = a[1]
957 if (h == 0) {
958 throw new IllegalStateException()
959 } else if (h == 1) {
960 r(t)
961 } else {
962 if (i(t)) {
963 throw new IllegalStateException()
964 }
965 if (h == 2) {
966 r(t[0])
967 } else if (h == 3) {
968 r(t[1])
969 } else {
970 fas([h.intdiv(2), t], { p ->
971 fas([2 + h.mod(2), p], { q ->
972 r(q)
973 })
974 })
975 }
976 }
979@Memoized
980def tar(def a) {
981 def r
982 tar(a, { r = it})
983 r
986@TailRecursive
987def tar(def a, def r) {
988 if (wut(a) == 1) {
989 throw new IllegalStateException()
990 }
991 def s = a[0]
992 def f = a[1]
993 if (wut(f) == 1) {
994 throw new IllegalStateException()
995 }
996 def o = f[0]
997 def v = f[1]
998 if (wut(o) == 0) {
999 tar([s, o], { p ->
1000 tar([s, v], { q ->
1001 r([p, q])
1002 })
1003 })
1004 } else {
1005 if (o == 0) {
1006 r(fas([v, s]))
1007 } else if (o == 1) {
1008 r(v)
1009 } else if (o == 3) {
1010 tar([s, v], {
1011 r(wut(it))
1012 })
1013 } else if (o == 4) {
1014 tar([s, v], {
1015 r(lus(it))
1016 })
1017 } else if (o == 5) {
1018 tar([s, v], {
1019 r(tis(it))
1020 })
1021 } else {
1022 if (wut(v) == 1) {
1023 throw new IllegalStateException()
1025 def x = v[0]
1026 def y = v[1]
1027 if (o == 2) {
1028 tar([s, x], { p ->
1029 tar([s, y], { q ->
1030 tar([p, q], {
1031 r(it)
1032 })
1033 })
1034 })
1035 } else if (o == 7) {
1036 tar(n([s, 2, x, 1, y]), {
1037 r(it)
1038 })
1039 } else if (o == 8) {
1040 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1041 r(it)
1042 })
1043 } else if (o == 9) {
1044 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1045 r(it)
1046 })
1047 } else if (o == 10) {
1048 if (wut(x) == 1) {
1049 tar([s, y], {
1050 r(it)
1051 })
1052 } else {
1053 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1054 r(it)
1055 })
1057 } else {
1058 if (wut(y) == 1) {
1059 throw new IllegalStateException()
1061 if (o == 6) {
1062 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1063 r(it)
1064 })
1065 } else {
1066 throw new IllegalStateException()
1072```
1074## Haskell
1076From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
1078```
1079module Language.Nock5K.Spec where
1080import Control.Monad.Instances
1082wut (a :- b) = return $ Atom 0
1083wut a = return $ Atom 1
1085lus (a :- b) = Left "+[a b]"
1086lus (Atom a) = return $ Atom (1 + a)
1088tis (a :- a') | a == a' = return $ Atom 0
1089tis (a :- b) = return $ Atom 1
1090tis a = Left "=a"
1092fas (Atom 1 :- a) = return a
1093fas (Atom 2 :- a :- b) = return a
1094fas (Atom 3 :- a :- b) = return b
1095fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
1096 fas $ Atom (2 + (a `mod` 2)) :- x
1097fas a = Left "/a"
1099tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
1100 y <- tar (a :- d)
1101 return $ x :- y
1103tar (a :- Atom 0 :- b) = fas $ b :- a
1104tar (a :- Atom 1 :- b) = return b
1105tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
1106 y <- tar (a :- c)
1107 tar $ x :- y
1108tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
1109tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
1110tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
1112tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
1113 Atom 2 :- (Atom 1 :- c :- d) :-
1114 (Atom 1 :- Atom 0) :- Atom 2 :-
1115 (Atom 1 :- Atom 2 :- Atom 3) :-
1116 (Atom 1 :- Atom 0) :- Atom 4 :-
1117 Atom 4 :- b)
1118tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
1119tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
1120 ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
1121 Atom 0 :- Atom 1) :- c)
1122tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
1123 (Atom 0 :- Atom 1) :- Atom 0 :- b)
1124tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
1125 (Atom 0 :- Atom 3) :- d)
1126tar (a :- Atom 10 :- b :- c) = tar (a :- c)
1128tar a = Left "*a"
1129```
1131## Hoon
1133```hoon
1134|= {sub/* fol/*}
1135^- *
1136?< ?=(@ fol)
1137?: ?=(^ -.fol)
1138 [$(fol -.fol) $(fol +.fol)]
1139?+ fol
1140 !!
1141 {$0 b/@}
1142 ?< =(0 b.fol)
1143 ?: =(1 b.fol) sub
1144 ?< ?=(@ sub)
1145 =+ [now=(cap b.fol) lat=(mas b.fol)]
1146 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1148 {$1 b/*}
1149 b.fol
1151 {$2 b/{^ *}}
1152 =+ ben=$(fol b.fol)
1153 $(sub -.ben, fol +.ben)
1155 {$3 b/*}
1156 =+ ben=$(fol b.fol)
1157 .?(ben)
1159 {$4 b/*}
1160 =+ ben=$(fol b.fol)
1161 ?> ?=(@ ben)
1162 +(ben)
1164 {$5 b/*}
1165 =+ ben=$(fol b.fol)
1166 ?> ?=(^ ben)
1167 =(-.ben +.ben)
1169 {$6 b/* c/* d/*}
1170 $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
1172 {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
1173 {$8 b/* c/*} $(fol =>(fol [7 [[7 [0 1] b] 0 1] c]))
1174 {$9 b/* c/*} $(fol =>(fol [7 c 2 [0 1] 0 b]))
1175 {$10 @ c/*} $(fol c.fol)
1176 {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
1178```
1180## JavaScript
1182From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1184```js
1185(function (self, factory) {
1186 'use strict'
1188 if (typeof define === 'function' && define.amd) {
1189 define([], factory)
1190 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1191 module.exports = factory()
1192 } else {
1193 self.nock = factory()
1195}(this, function () {
1196 'use strict'
1198 /**
1199 * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
1200 * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
1202 * @see http://urbit.org/docs/nock/definition/
1203 * @see https://media.urbit.org/whitepaper.pdf
1204 */
1206 var useMacros = false
1208 /*
1209 * code conventions:
1211 * `n` is a noun,
1212 * `s` is a subject noun,
1213 * `f` is a formula (or cell of formulas)
1214 */
1216 /* operators */
1218 /**
1219 * wut (?): test for atom (1) or cell (0)
1221 * ?[a b] 0
1222 * ?a 1
1223 */
1224 function wut (n) {
1225 return typeof n === 'number' ? 1 : 0
1228 /**
1229 * lus (+): increment an atom
1231 * +[a b] +[a b]
1232 * +a 1 + a
1233 */
1234 function lus (n) {
1235 if (wut(n) === 0) throw new Error('lus cell')
1236 return 1 + n
1239 /**
1240 * tis (=): test equality
1242 * =[a a] 0
1243 * =[a b] 1
1244 * =a =a
1245 */
1246 function tis (n) {
1247 if (wut(n) === 1) throw new Error('tis atom')
1248 return deepEqual(n[0], n[1]) ? 0 : 1
1251 /**
1252 * fas (/): resolve a tree address
1254 * /[1 a] a
1255 * /[2 a b] a
1256 * /[3 a b] b
1257 * /[(a + a) b] /[2 /[a b]]
1258 * /[(a + a + 1) b] /[3 /[a b]]
1259 * /a /a
1260 */
1261 function fas (addr, n) {
1262 if (n === undefined) throw new Error('invalid fas noun')
1263 if (addr === 0) throw new Error('invalid fas addr: 0')
1265 if (addr === 1) return n
1266 if (addr === 2) return n[0]
1267 if (addr === 3) return n[1]
1269 return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
1272 /* formulas */
1274 /**
1275 * slot (0): resolve a tree address
1277 * *[a 0 b] /[b a]
1278 */
1279 function slot (s, f) {
1280 var p = fas(f, s)
1282 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1284 return p
1287 /**
1288 * constant (1): return the formula regardless of subject
1290 * *[a 1 b] b
1291 */
1292 function constant (s, f) {
1293 return f
1296 /**
1297 * evaluate (2): evaluate the product of second formula against the product of the first
1299 * *[a 2 b c] *[*[a b] *[a c]]
1300 */
1301 function evaluate (s, f) {
1302 return nock(nock(s, f[0]), nock(s, f[1]))
1305 /**
1306 * cell (3): test if the product is a cell
1308 * *[a 3 b] ?*[a b]
1309 */
1310 function cell (s, f) {
1311 return wut(nock(s, f))
1314 /**
1315 * incr (4): increment the product
1317 * *[a 4 b] +*[a b]
1318 */
1319 function incr (s, f) {
1320 return lus(nock(s, f))
1323 /**
1324 * eq (5): test for equality between nouns in the product
1326 * *[a 5 b] =*[a b]
1327 */
1328 function eq (s, f) {
1329 return tis(nock(s, f))
1332 /* macro-formulas */
1334 /**
1335 * ife (6): if/then/else
1337 * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1338 */
1339 function macroIfe (s, f) {
1340 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]]]]]]]]]]])
1343 function ife (s, f) {
1344 var cond = nock(s, f[0])
1346 if (cond === 0) return nock(s, f[1][0])
1347 if (cond === 1) return nock(s, f[1][1])
1349 throw new Error('invalid ife conditional')
1352 /**
1353 * compose (7): evaluate formulas composed left-to-right
1355 * *[a 7 b c] *[a 2 b 1 c]
1356 */
1357 function macroCompose (s, f) {
1358 return nock(s, [2, [f[0], [1, f[1]]]])
1361 function compose (s, f) {
1362 // alternate form:
1363 // return nock(nock(s, f[0]), constant(s, f[1]))
1364 return nock(nock(s, f[0]), f[1])
1367 /**
1368 * extend (8): evaluate the second formula against [product of first, subject]
1370 * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
1371 */
1372 function macroExtend (s, f) {
1373 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1376 function extend (s, f) {
1377 // alternate form:
1378 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1379 return nock([nock(s, f[0]), s], f[1])
1382 /**
1383 * invoke (9): construct a core and evaluate one of its arms against it
1385 * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
1386 */
1387 function macroInvoke (s, f) {
1388 return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
1391 function invoke (s, f) {
1392 var prod = nock(s, f[1])
1393 return nock(prod, slot(prod, f[0]))
1396 /**
1397 * hint (10): skip first formula, evaluate second
1399 * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
1400 * *[a 10 b c] *[a c]
1401 */
1402 function macroHint (s, f) {
1403 if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
1404 return nock(s, f[1])
1407 function hint (s, f) {
1408 if (wut(f[0]) === 0) {
1409 if (wut(f[0][1]) === 1) throw new Error('invalid hint')
1410 nock(s, f[0][1])
1412 return nock(s, f[1])
1415 /* indexed formula functions */
1416 var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
1417 var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
1419 /**
1420 * nock (*)
1422 * the nock function
1424 * *[a [b c] d] [*[a b c] *[a d]]
1425 * *a *a
1426 */
1427 function nock (s, f) {
1428 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
1430 var idx = f[0]
1432 if (idx > 10) throw new Error('invalid formula: ' + idx)
1434 if (useMacros) return macroFormulas[idx](s, f[1])
1436 return formulas[idx](s, f[1])
1439 /* construct a JS noun (group an array into pairs, associating right) */
1440 function assoc (x) {
1441 if (!x.length) return x
1443 if (x.length === 1) return assoc(x[0])
1445 return [assoc(x[0]), assoc(x.slice(1))]
1448 /* deep equality for arrays or primitives */
1449 function deepEqual (a, b) {
1450 if (a === b) return true
1452 if (!(Array.isArray(a) && Array.isArray(b))) return false
1453 if (a.length !== b.length) return false
1455 for (var i = 0; i < a.length; i++) {
1456 if (!deepEqual(a[i], b[i])) return false
1459 return true
1462 /* parse a hoon-serialized nock formula and construct a JS noun */
1463 function parseNoun (x) {
1464 if (Array.isArray(x)) return assoc(x)
1466 if (typeof x === 'string') {
1467 var str = x.replace(/[\."']/g, '').split(' ').join(',')
1468 return assoc(JSON.parse(str))
1471 return x
1474 function nockInterface () {
1475 var args = [].slice.call(arguments)
1476 var subject, formula, noun
1478 if (args.length === 1) {
1479 formula = parseNoun(args[0])
1480 } else if (args.length === 2) {
1481 subject = parseNoun(args[0])
1482 formula = parseNoun(args[1])
1483 } else {
1484 noun = assoc(args)
1485 subject = noun[0]
1486 formula = noun[1]
1489 if (!formula) throw new Error('formula required')
1491 if (!subject) {
1492 // !=(~)
1493 subject = [1, 0]
1496 return nock(subject, formula)
1499 return {
1500 nock: nockInterface,
1501 _nock: nock,
1502 useMacros: function (arg) {
1503 useMacros = arg === undefined || arg
1504 return this
1505 },
1506 util: {
1507 assoc: assoc,
1508 parseNoun: parseNoun,
1509 deepEqual: deepEqual
1510 },
1511 operators: {
1512 wut: wut,
1513 lus: lus,
1514 tis: tis,
1515 fas: fas
1516 },
1517 formulas: {
1518 slot: slot,
1519 constant: constant,
1520 evaluate: evaluate,
1521 cell: cell,
1522 incr: incr,
1523 eq: eq,
1524 macroIfe: macroIfe,
1525 ife: ife,
1526 macroCompose: macroCompose,
1527 compose: compose,
1528 macroExtend: macroExtend,
1529 extend: extend,
1530 macroInvoke: macroInvoke,
1531 invoke: invoke,
1532 macroHint: macroHint,
1533 hint: hint
1536}))
1537```
1539## Python
1541From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1543```py
1544#!/usr/bin/env python3
1546# []
1547def l(*lst):
1548 if len(lst) == 1:
1549 return(lst[0], 0)
1550 if len(lst) == 2:
1551 return lst
1552 else:
1553 return (lst[0], l(*lst[1:]))
1555# *
1556def nock(noun):
1557 return tar(noun)
1559# ?
1560def wut(noun):
1561 if isinstance(noun, int):
1562 return 1
1563 else:
1564 return 0
1567# +
1568def lus(noun):
1569 if isinstance(noun, int):
1570 return 1 + noun
1571 else:
1572 return noun
1575# =
1576def tis(noun):
1577 if noun[0] == noun[1]:
1578 return 0
1579 else:
1580 return 1
1583# /
1584def slot(noun):
1585 if noun[0] == 1:
1586 return noun[1]
1587 elif noun[0] == 2:
1588 return noun[1][0]
1589 elif noun[0] == 3:
1590 return noun[1][1]
1591 elif noun[0] % 2 == 0:
1592 return slot((2, slot((noun[0] // 2, noun[1]))))
1593 elif noun[0] % 2 == 1:
1594 return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
1597def tar(noun):
1598 if isinstance(noun[1][0], int):
1599 if noun[1][0] == 0:
1600 return slot((noun[1][1], noun[0]))
1601 elif noun[1][0] == 1:
1602 return noun[1][1]
1603 elif noun[1][0] == 2:
1604 return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
1605 elif noun[1][0] == 3:
1606 return wut(nock((noun[0], noun[1][1])))
1607 elif noun[1][0] == 4:
1608 return lus(nock((noun[0], noun[1][1])))
1609 elif noun[1][0] == 5:
1610 return tis(nock((noun[0], noun[1][1])))
1611 elif noun[1][0] == 6:
1612 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]))
1613 elif noun[1][0] == 7:
1614 return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
1615 elif noun[1][0] == 8:
1616 return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
1617 elif noun[1][0] == 9:
1618 return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
1619 elif noun[1][0] == 10:
1620 if isinstance(noun[1][1][0], int):
1621 return nock((noun[0], noun[1][1][1]))
1622 else:
1623 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1624 else:
1625 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1626```
1628## Ruby
1630From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1632```ruby
1633def str_to_tree(str)
1634 arr = []
1635 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1636 end
1637end
1639def max_depth(arr)
1640 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1641 ret
1642end
1644def pp(arr)
1645 depth = max_depth(arr)
1646 space = 128
1647 1.up_to(8) do |depth|
1648 space = space / 2
1649 min = 2 ** (depth - 1)
1650 max = (2 ** depth) - 1
1651 min.upto(max) { |axis|
1652 end
1654end
1656def norm(arr)
1657 return arr unless arr.is_a?(Array)
1658 while arr.size > 2
1659 size = arr.size
1660 arr[size - 2] = [ arr[size - 2], arr.pop ]
1661 end
1662 arr = arr.map { |x| norm(x) }
1663end
1665def wut(arr)
1666 arr.is_a?(Array) ? YES : NO
1667end
1669def lus(atom)
1670 raise "not an atom" unless atom.is_a?(Fixnum)
1671 atom + 1
1672end
1674def tis(arr)
1675 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1676 ( arr[0] == arr[1] ) ? YES : NO
1677end
1679def slot(axis, arr, allow_error = true)
1680 raise "axis on atom" unless arr.is_a?(Array)
1681 return arr if axis == 1
1682 return arr[0] if axis == 2
1683 return arr[1] if axis == 3
1684 return slot(2, slot(axis/2, arr)) if (axis %2) == 0
1685 return slot(3, slot(axis/2, arr))
1686end
1689def nock(arr)
1690 raise "error: nocking an atom" unless arr.is_a?(Array)
1692 oper = slot(4, arr)
1693 a = slot(2, arr)
1694 b = slot(5, arr)
1696 if oper.is_a?(Array)
1697 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1698 end
1701 case oper
1702 when 0 then
1703 slot(b,a )
1705 when 1 then
1708 when 2 then
1709 b_prime = slot(2, b)
1710 c = slot(3,b)
1711 nock( [ nock([a, b_primce]), nock([a, c]) ])
1713 when 3 then
1714 wut(nock([a, b]))
1716 when 4 then
1717 lus(nock([a, b]))
1719 when 5 then
1720 tis(nock([a, b]))
1722 when 6 then
1723 b_prime = slot(2, b)
1724 c = slot(6,b)
1725 d = slot(7,b)
1726 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1728 when 7 then
1729 b_prime = slot(2, b)
1730 c = slot(3,b)
1731 nock( norm ([a, 2, b_prime, 1, c]))
1733 when 8 then
1734 b_prime = slot(2, b)
1735 c = slot(3,b)
1736 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1738 when 9 then
1739 b_prime = slot(2, b)
1740 c = slot(3,b)
1741 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1743 when 10 then
1744 if wut(slot(2,b)) == TRUE
1745 b_prime = slot(4, b)
1746 c = slot(5, b)
1747 d = slot(3, b)
1748 c = slot(3,b)
1749 nock( norm ([a, 8, c, 7, [0, 3], d]))
1750 else
1751 b_prime = slot(2, b)
1752 c = slot(3, b)
1753 nock( norm ([a, 10, [b, c]]))
1754 end
1755 else
1756 raise "error: unknown opcode #{oper.inspect}"
1757 end
1758end
1759```
1761## Scala
1763From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
1765```scala
1766package object nnnock {
1768 sealed trait Noun;
1769 case class Atom( value : Int ) extends Noun;
1770 case class Cell( head : Noun, tail : Noun ) extends Noun;
1771 implicit def toAtom( value : Int ) : Atom = Atom( value );
1772 implicit def toInt( atom : Atom ) : Int = atom.value;
1774 def nock( a : Noun ) : Noun = *(a)
1777 object Cell {
1778 private def apply( nl : List[Noun] ) : Cell = {
1779 nl match {
1780 case a :: b :: Nil => Cell(a, b);
1781 case a :: b :: c :: Nil => Cell(a, Cell(b, c));
1782 case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
1785 def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
1788 def ?( noun : Noun ) : Noun = noun match {
1789 case _ : Cell => 0;
1790 case _ : Atom => 1;
1793 @tailrec def plus( noun : Noun ) : Noun = noun match {
1794 case a : Atom => 1 + a;
1795 case c : Cell => plus( c ); //intentional endless spin
1798 def heq( noun : Noun ) : Atom = noun match {
1799 case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
1800 case Cell( a : Cell, b : Atom ) => 1;
1801 case Cell( a : Atom, b : Cell ) => 1;
1802 case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
1803 case a : Atom => heq( a ); //intentional endless spin
1806 def /( noun : Noun ) : Noun = noun match {
1807 case Cell(Atom(1), a) => a;
1808 case Cell(Atom(2), Cell(a, b)) => a;
1809 case Cell(Atom(3), Cell(a, b)) => b;
1810 case Cell(Atom(value), b ) => {
1811 val a = value / 2;
1812 val num = if ( value % a == 0 ) 2 else 3;
1813 /(Cell(num, /(Cell(a, b))));
1815 case a => /( a ); //intentional endless spin
1819 def *( noun : Noun ) : Noun = noun match {
1820 case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
1821 case Cell( a, Cell(Atom(value), tail) ) => {
1822 (value, tail) match {
1823 case (0, b) => /( Cell(b, a) );
1824 case (1, b) => b;
1825 case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
1826 case (3, b) => ?( *( Cell(a,b) ) );
1827 case (4, b) => plus( *( Cell(a,b) ) );
1828 case (5, b) => heq( *( Cell(a,b) ) );
1829 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?
1830 case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
1831 case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
1832 case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
1833 case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
1834 case (10, Cell(b, c)) => *( Cell(a,c) );
1835 case _ => *( noun ); //intentional endless spin
1838 case a => *( a ); //intentional endless spin
1841```
1843## Scheme
1845From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
1847```scheme
1848(import (rnrs (6)))
1850(define (i a) a)
1852(define (n a r)
1853 (cond
1854 ((list? a)
1855 (let ((l (length a)))
1856 (cond
1857 ((equal? l 0) (raise 1))
1858 ((equal? l 1) (r (car a)))
1859 (else
1860 (let ((t (cond
1861 ((equal? l 2) (cadr a))
1862 (else (cdr a)))))
1863 (n (car a)
1864 (lambda (p) (n t
1865 (lambda (q) (r (cons p q)))))))))))
1866 ((fixnum? a) (r a))
1867 (else (raise 2))))
1869(define (wut a)
1870 (cond
1871 ((fixnum? a) 1)
1872 (else 0)))
1874(define (lus a)
1875 (cond
1876 ((equal? (wut a) 0) (raise 3))
1877 (else (+ 1 a))))
1879(define (tis a)
1880 (cond
1881 ((equal? (wut a) 1) (raise 4))
1882 ((equal? (car a) (cdr a)) 0)
1883 (else 1)))
1885(define (fas a r)
1886 (cond
1887 ((equal? (wut a) 1) (raise 5))
1888 (else
1889 (let ((h (car a))
1890 (t (cdr a)))
1891 (cond
1892 ((not (fixnum? h)) (raise 6))
1893 ((equal? h 0) (raise 7))
1894 ((equal? h 1) (r t))
1895 ((fixnum? t) (raise 8))
1896 ((equal? h 2) (r (car t)))
1897 ((equal? h 3) (r (cdr t)))
1898 (else
1899 (fas (cons (div h 2) t)
1900 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
1901 (lambda (q) (r q)))))))))))
1903(define (tar a r)
1904 (cond
1905 ((equal? (wut a) 1) (raise 9))
1906 (else
1907 (let ((s (car a))
1908 (f (cdr a)))
1909 (cond
1910 ((equal? (wut f) 1) (raise 10))
1911 (else
1912 (let ((o (car f))
1913 (v (cdr f)))
1914 (cond
1915 ((equal? (wut o) 0) (tar (cons s o)
1916 (lambda (p) (tar (cons s v)
1917 (lambda (q) (r (cons p q)))))))
1918 ((equal? o 0) (r (fas (cons v s) i)))
1919 ((equal? o 1) (r v))
1920 ((equal? o 3) (tar (cons s v)
1921 (lambda (p) (r (wut p)))))
1922 ((equal? o 4) (tar (cons s v)
1923 (lambda (p) (r (lus p)))))
1924 ((equal? o 5) (tar (cons s v)
1925 (lambda (p) (r (tis p)))))
1926 ((equal? (wut v) 1) (raise 11))
1927 (else
1928 (let ((x (car v))
1929 (y (cdr v)))
1930 (cond
1931 ((equal? o 2) (tar (cons s x)
1932 (lambda (p) (tar (cons s y)
1933 (lambda (q) (tar (cons p q)
1934 (lambda (u) (r u))))))))
1935 ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
1936 (lambda (p) (r p))))
1937 ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
1938 (lambda (p) (r p))))
1939 ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
1940 (lambda (p) (r p))))
1941 ((equal? o 10) (cond
1942 ((equal? (wut x) 1) (tar (cons s y)
1943 (lambda (p) (r p))))
1944 (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
1945 (lambda (p) (r p))))))
1946 ((equal? (wut y) 1) (raise 12))
1947 ((equal? o 6) (tar (n (list
1948 (list s)
1950 (list 0 1)
1952 (list 1 (list (car y)) (list (cdr y)))
1953 (list 1 0)
1955 (list 1 2 3)
1956 (list 1 0)
1959 (list x))
1960 i)
1961 (lambda (p) (r p))))
1962 (else (raise 13)))))))))))))
1963```
1965## Swift
1967```swift
1968import Foundation
1969// 1 :: A noun is an atom or a cell.
1970// 2 :: An atom is a natural number.
1971// 3 :: A cell is an ordered pair of nouns.
1972// 4
1973// 5 :: nock(a) *a
1974// 6 :: [a b c] [a [b c]]
1975// 7
1976// 8 :: ?[a b] 0
1977// 9 :: ?a 1
1978// 10 :: +[a b] +[a b]
1979// 11 :: +a 1 + a
1980// 12 :: =[a a] 0
1981// 13 :: =[a b] 1
1982// 14 :: =a =a
1983// 15
1984// 16 :: /[1 a] a
1985// 17 :: /[2 a b] a
1986// 18 :: /[3 a b] b
1987// 19 :: /[(a + a) b] /[2 /[a b]]
1988// 20 :: /[(a + a + 1) b] /[3 /[a b]]
1989// 21 :: /a /a
1990// 22
1991// 23 :: *[a [b c] d] [*[a b c] *[a d]]
1992// 24
1993// 25 :: *[a 0 b] /[b a]
1994// 26 :: *[a 1 b] b
1995// 27 :: *[a 2 b c] *[*[a b] *[a c]]
1996// 28 :: *[a 3 b] ?*[a b]
1997// 29 :: *[a 4 b] +*[a b]
1998// 30 :: *[a 5 b] =*[a b]
1999// 31
2000// 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]
2001// 33 :: *[a 7 b c] *[a 2 b 1 c]
2002// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2003// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2004// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2005// 37 :: *[a 10 b c] *[a c]
2006// 38
2007// 39 :: *a *a
2009// 1 :: A noun is an atom or a cell.
2010public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
2012 // 2 :: An atom is a natural number.
2013 public typealias ATOM = UIntMax
2015 case Atom(ATOM)
2016 // 3 :: A cell is an ordered pair of nouns.
2017 case Cell(Noun, Noun)
2018 case Invalid
2020 public static var YES: Noun { return .Atom(0) }
2021 public static var NO: Noun { return .Atom(1) }
2023 public init(_ noun: Noun) { self = noun }
2025 // 6 :: [a b c] [a [b c]]
2026 public init(_ nouns: [Noun]) {
2027 self = .Invalid
2028 if nouns.count > 0 {
2029 var reverse = nouns.reverse().generate()
2030 self = reverse.next()!
2031 while let n = reverse.next() {
2032 self = .Cell(n, self)
2037 // protocol IntegerLiteralConvertible
2038 public typealias IntegerLiteralType = ATOM
2039 public init(integerLiteral value: IntegerLiteralType) {
2040 self = .Atom(value)
2043 // protocol ArrayLiteralConvertible
2044 public typealias Element = Noun
2045 public init(arrayLiteral elements: Element...) {
2046 self = Noun(elements)
2049 // Array subscript
2050 public subscript(axis: ATOM) -> Noun {
2051 return fas(.Cell(.Atom(axis), self))
2054 // protocol Hashable
2055 public var hashValue: Int {
2056 //return self.description.hashValue
2057 switch self {
2058 case let .Atom(a):
2059 return a.hashValue
2060 case let .Cell(a, b):
2061 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2062 default:
2063 abort()
2067 // protocol CustomStringConvertible
2068 public var description: String {
2069 return describe()
2072 private func describe(depth: Int = 0) -> String {
2073 var sub = ""
2074 let next = depth+1
2075 switch self {
2076 case .Invalid:
2077 return "[%INVALID%]"
2078 case let .Atom(atom):
2079 return "\(atom)"
2080 case let .Cell(.Cell(a, b), c):
2081 sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
2082 case let .Cell(a, b):
2083 sub = "\(a.describe(next)) \(b.describe(next))"
2085 return depth == 0 ? "[\(sub)]" : sub
2089// protocol Equatable
2090public func == (left: Noun, right: Noun) -> Bool
2092 switch (left, right) {
2093 case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
2094 case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
2095 case (.Invalid, .Invalid): return true
2096 default: return false
2100public func wut(noun: Noun) -> Noun
2102 switch noun {
2103 // 8 :: ?[a b] 0
2104 case .Cell:
2105 return Noun.YES
2106 case .Atom:
2107 // 9 :: ?a 1
2108 return Noun.NO
2109 default:
2110 //return wut(noun)
2111 abort()
2115public func lus(noun: Noun) -> Noun
2117 if case let .Atom(a) = noun {
2118 // 11 :: +a 1 + a
2119 return .Atom(1+a)
2121 // 10 :: +[a b] +[a b]
2122 //return lus(noun)
2123 abort()
2126public func tis(noun: Noun) -> Noun
2128 if case let .Cell(a, b) = noun {
2129 // 12 :: =[a a] 0
2130 // 13 :: =[a b] 1
2131 return (a == b) ? Noun.YES : Noun.NO
2133 // 14 :: =a =a
2134 //return tis(noun)
2135 abort()
2138public func fas(noun: Noun) -> Noun
2140 switch noun {
2141 // 16 :: /[1 a] a
2142 case let .Cell(1, a):
2143 return a
2144 // 17 :: /[2 a b] a
2145 case let .Cell(2, .Cell(a, _)):
2146 return a
2147 // 18 :: /[3 a b] b
2148 case let .Cell(3, .Cell(_, b)):
2149 return b
2150 // 19 :: /[(a + a) b] /[2 /[a b]]
2151 // 20 :: /[(a + a + 1) b] /[3 /[a b]]
2152 case let .Cell(.Atom(axis), tree):
2153 let inner = Noun.Atom(axis / 2)
2154 let outer = Noun.Atom(2 + (axis % 2))
2155 return fas(.Cell(outer, fas(.Cell(inner, tree))))
2156 default:
2157 // 21 :: /a /a
2158 //return fas(noun)
2159 abort()
2163public func tar(noun: Noun) -> Noun
2165 switch noun {
2166 case let .Cell(a, formula):
2167 switch formula {
2168 // 23 :: *[a [b c] d] [*[a b c] *[a d]]
2169 case let .Cell(.Cell(b, c), d):
2170 return .Cell(tar([a, b, c]), tar([a, d]))
2172 // 25 :: *[a 0 b] /[b a]
2173 case let .Cell(0, b):
2174 return fas([b, a])
2176 // 26 :: *[a 1 b] b
2177 case let .Cell(1, b):
2178 return b
2180 // 27 :: *[a 2 b c] *[*[a b] *[a c]]
2181 case let .Cell(2, .Cell(b, c)):
2182 return tar([tar([a, b]), tar([a, c])])
2184 // 28 :: *[a 3 b] ?*[a b]
2185 case let .Cell(3, b):
2186 return wut(tar([a, b]))
2188 // 29 :: *[a 4 b] +*[a b]
2189 case let .Cell(4, b):
2190 return lus(tar([a, b]))
2192 // 30 :: *[a 5 b] =*[a b]
2193 case let .Cell(5, b):
2194 return tis(tar([a, b]))
2196 // 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]
2197 case let .Cell(6, .Cell(b, .Cell(c, d))):
2198 return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
2200 // 33 :: *[a 7 b c] *[a 2 b 1 c]
2201 case let .Cell(7, .Cell(b, c)):
2202 return tar([a, 2, b, 1, c])
2204 // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2205 case let .Cell(8, .Cell(b, c)):
2206 return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
2208 // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2209 case let .Cell(9, .Cell(b, c)):
2210 return tar([a, 7, c, 2, [0, 1], 0, b])
2212 // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2213 case let .Cell(10, .Cell(.Cell(_, c), d)):
2214 return tar([a, 8, c, 7, [0, 3], d])
2216 // 37 :: *[a 10 b c] *[a c]
2217 case let .Cell(10, .Cell(_, c)):
2218 return tar([a, c]);
2220 default:
2221 //return tar(noun)
2222 abort()
2224 default:
2225 //return tar(noun)
2226 abort()
2231public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2233public func dao(formula: Noun) -> Noun->Noun
2235 if let cached = nock_functions[formula] {
2236 return cached
2239 let compiler = { () -> Noun -> Noun in
2240 switch formula {
2241 case let .Cell(.Cell(b, c), d): // Distribution
2242 let (p, q) = (dao(.Cell(b, c)), dao(d))
2243 return { a in .Cell(p(a), q(a)) }
2245 case let .Cell(0, b): // Axis
2246 return { a in fas(.Cell(b, a)) }
2248 case let .Cell(1, b): // Just
2249 return { _ in b }
2251 case let .Cell(2, .Cell(b, c)): // Fire
2252 let (f, g) = (dao(b), dao(c))
2253 return { a in dao(g(a))(f(a)) }
2255 case let .Cell(3, b): // Depth
2256 let f = dao(b)
2257 return { a in wut(f(a)) }
2259 case let .Cell(4, b): // Bump
2260 let f = dao(b)
2261 return { a in lus(f(a)) }
2263 case let .Cell(5, b): // Same
2264 let f = dao(b)
2265 return { a in tis(f(a)) }
2267 case let .Cell(6, .Cell(b, .Cell(c, d))): // If
2268 let (p, q, r) = (dao(b), dao(c), dao(d))
2269 return { a in
2270 switch p(a) {
2271 case Noun.self.YES:
2272 return q(a)
2273 case Noun.self.NO:
2274 return r(a)
2275 default:
2276 return tar(.Cell(a, formula))
2280 case let .Cell(7, .Cell(b, c)): // Compose
2281 let (f, g) = (dao(b), dao(c))
2282 return { a in g(f(a)) }
2284 case let .Cell(8, .Cell(b, c)): // Push
2285 let (f, g) = (dao(b), dao(c))
2286 return { a in g(.Cell(f(a), a)) }
2288 case let .Cell(9, .Cell(b, c)): // Call
2289 let f = dao(c)
2290 return { a in
2291 let core = f(a)
2292 let arm = dao(fas(.Cell(b, core)))
2293 return arm(core)
2296 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2297 let ignore = dao(c)
2298 let f = dao(d)
2299 return { a in ignore(a); return f(a) }
2301 case let .Cell(10, .Cell(_, c)): // Hint
2302 let f = dao(c)
2303 return { a in f(a) }
2305 default:
2306 return { a in tar(.Cell(a, formula)) }
2310 let r = compiler()
2311 nock_functions[formula] = r
2312 return r
2315public func nock(n: Noun) -> Noun
2317 if case let .Cell(a, b) = n {
2318 let f = dao(b)
2319 return f(a)
2321 return nock(n)
2323```