on be21ded help sign in
urbit.org/nock/implementations.md
2321 lines 65 kB history raw
1+++
2title = "Implementations"
3weight = 4
4template = "doc.html"
5+++
6We 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.):
8## Table of Contents
10- [C](#C)
12- [Clojure](#clojure)
14- [C#](#c-sharp)
16- [Groovy](#groovy)
18- [Haskell](#haskell)
20- [JavaScript](#javascript)
22- [Python](#python)
24- [Ruby](#ruby)
26- [Scala](#scala)
28- [Scheme](#scheme)
30- [Swift](#swift)
32## C Implementation
34The actual production Nock interpreter. Note gotos for tail-call elimination,
35and manual reference counting. More about the C environment can be found
36in the [runtime system documentation](@/docs/vere/runtime.md).
37```
38/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
39*/
40static u3_noun
41_n_nock_on(u3_noun bus, u3_noun fol)
43 u3_noun hib, gal;
45 while ( 1 ) {
46 hib = u3h(fol);
47 gal = u3t(fol);
49#ifdef U3_CPU_DEBUG
50 u3R->pro.nox_d += 1;
51#endif
53 if ( c3y == u3r_du(hib) ) {
54 u3_noun poz, riv;
56 poz = _n_nock_on(u3k(bus), u3k(hib));
57 riv = _n_nock_on(bus, u3k(gal));
59 u3a_lose(fol);
60 return u3i_cell(poz, riv);
61 }
62 else switch ( hib ) {
63 default: return u3m_bail(c3__exit);
65 case 0: {
66 if ( c3n == u3r_ud(gal) ) {
67 return u3m_bail(c3__exit);
68 }
69 else {
70 u3_noun pro = u3k(u3at(gal, bus));
72 u3a_lose(bus); u3a_lose(fol);
73 return pro;
74 }
75 }
76 c3_assert(!"not reached");
78 case 1: {
79 u3_noun pro = u3k(gal);
81 u3a_lose(bus); u3a_lose(fol);
82 return pro;
83 }
84 c3_assert(!"not reached");
86 case 2: {
87 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
88 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
90 u3a_lose(fol);
91 bus = seb;
92 fol = nex;
93 continue;
94 }
95 c3_assert(!"not reached");
97 case 3: {
98 u3_noun gof, pro;
100 gof = _n_nock_on(bus, u3k(gal));
101 pro = u3r_du(gof);
103 u3a_lose(gof); u3a_lose(fol);
104 return pro;
105 }
106 c3_assert(!"not reached");
108 case 4: {
109 u3_noun gof, pro;
111 gof = _n_nock_on(bus, u3k(gal));
112 pro = u3i_vint(gof);
114 u3a_lose(fol);
115 return pro;
116 }
117 c3_assert(!"not reached");
119 case 5: {
120 u3_noun wim = _n_nock_on(bus, u3k(gal));
121 u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
123 u3a_lose(wim); u3a_lose(fol);
124 return pro;
125 }
126 c3_assert(!"not reached");
128 case 6: {
129 u3_noun b_gal, c_gal, d_gal;
131 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
132 {
133 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
134 u3_noun nex;
136 if ( 0 == tys ) {
137 nex = u3k(c_gal);
138 } else if ( 1 == tys ) {
139 nex = u3k(d_gal);
140 } else return u3m_bail(c3__exit);
142 u3a_lose(fol);
143 fol = nex;
144 continue;
145 }
146 }
147 c3_assert(!"not reached");
149 case 7: {
150 u3_noun b_gal, c_gal;
152 u3x_cell(gal, &b_gal, &c_gal);
153 {
154 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
155 u3_noun nex = u3k(c_gal);
157 u3a_lose(fol);
158 bus = bod;
159 fol = nex;
160 continue;
161 }
162 }
163 c3_assert(!"not reached");
165 case 8: {
166 u3_noun b_gal, c_gal;
168 u3x_cell(gal, &b_gal, &c_gal);
169 {
170 u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
171 u3_noun bod = u3nc(heb, bus);
172 u3_noun nex = u3k(c_gal);
174 u3a_lose(fol);
175 bus = bod;
176 fol = nex;
177 continue;
178 }
179 }
180 c3_assert(!"not reached");
182 case 9: {
183 u3_noun b_gal, c_gal;
185 u3x_cell(gal, &b_gal, &c_gal);
186 {
187 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
188 u3_noun pro;
190 u3t_off(noc_o);
191 pro = u3j_kick(seb, b_gal);
192 u3t_on(noc_o);
194 if ( u3_none != pro ) {
195 u3a_lose(fol);
196 return pro;
197 }
198 else {
199 if ( c3n == u3r_ud(b_gal) ) {
200 return u3m_bail(c3__exit);
201 }
202 else {
203 u3_noun nex = u3k(u3at(b_gal, seb));
205 u3a_lose(fol);
206 bus = seb;
207 fol = nex;
208 continue;
209 }
210 }
211 }
212 }
213 c3_assert(!"not reached");
215 case 10: {
216 u3_noun p_gal, q_gal;
218 u3x_cell(gal, &p_gal, &q_gal);
219 {
220 u3_noun zep, hod, nex;
222 if ( c3y == u3r_du(p_gal) ) {
223 u3_noun b_gal = u3h(p_gal);
224 u3_noun c_gal = u3t(p_gal);
225 u3_noun d_gal = q_gal;
227 zep = u3k(b_gal);
228 hod = _n_nock_on(u3k(bus), u3k(c_gal));
229 nex = u3k(d_gal);
230 }
231 else {
232 u3_noun b_gal = p_gal;
233 u3_noun c_gal = q_gal;
235 zep = u3k(b_gal);
236 hod = u3_nul;
237 nex = u3k(c_gal);
238 }
240 u3a_lose(fol);
241 return _n_hint(zep, hod, bus, nex);
242 }
243 }
245 case 11: {
246 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
247 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
248 u3_noun val;
250 u3t_off(noc_o);
251 val = u3m_soft_esc(ref, u3k(gof));
252 u3t_on(noc_o);
254 if ( !_(u3du(val)) ) {
255 u3m_bail(u3nt(1, gof, 0));
256 }
257 if ( !_(u3du(u3t(val))) ) {
258 //
259 // replace with proper error stack push
260 //
261 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
262 return u3m_bail(c3__exit);
263 }
264 else {
265 u3_noun pro;
267 u3z(gof);
268 u3z(fol);
269 pro = u3k(u3t(u3t(val)));
270 u3z(val);
272 return pro;
273 }
274 }
275 c3_assert(!"not reached");
276 }
277 }
279```
281## Clojure
283From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
285```
286(ns anock.core
287 (:import anock.NockException))
289(declare atom? cell? cell)
291(defn noun?
292 "A noun is an atom or a cell."
293 [noun & ns]
294 (if ns false
295 (or (atom? noun) (cell? noun))))
297(defn atom?
298 "An atom is a natural number."
299 [noun & ns]
300 (if ns false
301 (and (integer? noun) (>= noun 0))))
303(defn cell?
304 "A cell is an ordered pair of nouns."
305 [noun]
306 (cond
307 (atom? noun) false
308 (nil? noun) false
309 (not= 2 (count noun)) false
310 :else (and (noun? (first noun))
311 (noun? (second noun)))))
313(defn tis
314 "= (pronounced 'tis') tests a cell for equality."
315 [noun]
316 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
317 (let [[a b] noun]
318 (if (= a b) 0 1))))
320(defn wut
321 "? (pronounced 'wut') tests whether a noun is a cell."
322 [noun]
323 (cond
324 (atom? noun) 1
325 (cell? noun) 0
326 :else (throw (anock.NockException. "Invalid noun."))))
328(defn lus
329 "+ (pronounced 'lus') adds 1 to an atom."
330 [noun]
331 (if (atom? noun) (inc noun)
332 (throw (anock.NockException. "Can only lus atoms."))))
334(defn fas
335 "/ (pronounced 'fas') is a tree address function."
336 [noun]
337 (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
338 (let [[a b] (cell noun)]
339 (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
340 (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
341 (throw (anock.NockException. (str "Cannot fas noun: " noun))))
342 (cond
343 (= 1 a) b
344 (= 2 a) (first b)
345 (= 3 a) (second b)
346 (even? a) (fas [2 (fas [(/ a 2) b])])
347 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
349(defn tar
350 "* (pronounced 'tar') means Nock"
351 [noun]
352 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
353 (try
354 (let [noun (cell noun) [x [y z]] noun]
355 (cond
356 (cell? y) (cell (tar [x y]) (tar [x z]))
357 (zero? y) (fas [z x])
358 (= 1 y) z
359 (= 3 y) (wut (tar [x z]))
360 (= 4 y) (lus (tar [x z]))
361 (= 5 y) (tis (tar [x z]))
362 :else (let [[p q] z]
363 (cond
364 (= 2 y) (tar [(tar [x p]) (tar [x q])])
365 (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
366 [1 0] 2 [1 2 3] [1 0] 4 4 p])
367 (= 7 y) (tar [x 2 p 1 q])
368 (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
369 (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
370 (= 10 y) (if (cell? p)
371 (tar [x 8 (second p) 7 [0 3] q])
372 (tar [x q]))))))
373 (catch RuntimeException e
374 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
376(def nock tar)
378; Some convenience functions
379(defn apply* [f x]
380 (if (and (= 1 (count x)) (coll? (first x)))
381 (apply f x)
382 (f x)))
384(defn bracket
385 "[a b c] -> [a [b c]]"
386 [[a & b :as c]]
387 (let [b (vec b)]
388 (cond
389 (and (noun? a) (apply noun? b)) (vec c)
390 (apply noun? b) (apply vector (bracket a) b)
391 (noun? a) [a (apply* bracket b)]
392 :else [(bracket a) (apply* bracket b)])))
394(defn cell [& nouns]
395 (if (apply atom? nouns)
396 (throw (anock.NockException. "Cannot convert atom to cell."))
397 (apply* bracket nouns)))
398```
400## C#
402From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
404```
405using System;
406using System.Collections.Generic;
407using System.Linq;
408using System.Text;
409using System.Text.RegularExpressions;
411namespace NockInterpreter
413 class Interpreter
414 {
415 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
417 public static Noun Nock(Noun noun)
418 {
419 Start:
420 Noun cache_noun;
421 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
422 {
423 return cache_noun;
424 }
426 if (Atom.IsAtom(noun))
427 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
428 else
429 {
430 Noun subject = noun.n1;
431 if (Noun.IsCell(noun.n2))
432 {
433 Cell formula = (Cell)noun.n2;
434 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
435 {
436 Atom op = (Atom)formula.n1;
437 Noun operands = formula.n2;
439 switch (op.value)
440 {
441 case 0: // 25 :: *[a 0 b] /[b a]
442 memocache[noun.ToString()] = fas(operands, subject);
443 return memocache[noun.ToString()];
444 case 1: // 26 :: *[a 1 b] b
445 memocache[noun.ToString()] = operands;
446 return memocache[noun.ToString()];
447 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
448 if (Noun.IsCell(operands))
449 {
450 Noun a = Nock(subject, operands.n1);
451 Noun b = Nock(subject, operands.n2);
452 noun = Noun.CreateNoun(a, b);
453 goto Start;
454 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
455 }
456 throw new Exception("Atom after operand 2: " + operands.ToString());
457 case 3: // 28 :: *[a 3 b] ?*[a b]
458 memocache[noun.ToString()] = wut(Nock(subject, operands));
459 return memocache[noun.ToString()];
460 case 4: // 29 :: *[a 4 b] +*[a b]
461 memocache[noun.ToString()] = lus(Nock(subject, operands));
462 return memocache[noun.ToString()];
463 case 5: // 30 :: *[a 5 b] =*[a b]
464 memocache[noun.ToString()] = tis(Nock(subject, operands));
465 return memocache[noun.ToString()];
466 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]
467 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
468 {
469 Noun b = operands.n1;
470 Noun c = operands.n2.n1;
471 Noun d = operands.n2.n2;
472 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
473 goto Start;
474 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
475 }
476 throw new Exception("Unhandled pattern for operand 6");
477 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
478 if (Noun.IsCell(operands))
479 {
480 Noun b = operands.n1;
481 Noun c = operands.n2;
482 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
483 goto Start;
484 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
485 }
486 throw new Exception("Atom after operand 7: " + operands.ToString());
487 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
488 if (Noun.IsCell(operands))
489 {
490 Noun b = operands.n1;
491 Noun c = operands.n2;
492 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
493 goto Start;
494 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
495 }
496 throw new Exception("Atom after operand 8: " + operands.ToString());
497 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
498 if (Noun.IsCell(operands))
499 {
500 Noun b = operands.n1;
501 Noun c = operands.n2;
502 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
503 goto Start;
504 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
505 }
506 throw new Exception("Atom after operand 9: " + operands.ToString());
507 case 10:
508 if (Noun.IsCell(operands))
509 {
510 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
511 {
512 Noun b = operands.n1.n1;
513 Noun c = operands.n1.n2;
514 Noun d = operands.n2;
515 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
516 goto Start;
517 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
518 }
519 else // 37 :: *[a 10 b c] *[a c]
520 {
521 Noun c = operands.n2;
522 noun = Noun.CreateNoun(subject, c);
523 goto Start;
524 // return Nock(subject, c);
525 }
526 }
527 throw new Exception("Atom after operand 10: " + operands.ToString());
528 default:
529 throw new Exception("Unknown operand: " + op.value);
530 }
531 }
532 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
533 {
534 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
535 return memocache[noun.ToString()];
536 }
537 }
538 }
539 throw new Exception("Unhandled pattern");
540 }
542 public static Noun Nock(string program)
543 {
544 Noun noun = Noun.CreateNoun(program);
545 return Nock(noun);
546 }
548 public static Noun Nock(Noun n1, Noun n2)
549 {
550 Noun noun = Noun.CreateNoun(n1, n2);
551 return Nock(noun);
552 }
554 private static Noun tis(Noun noun)
555 {
556 if (Noun.IsAtom(noun.ToString()))
557 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
558 else
559 {
560 Cell cell = (Cell)noun;
562 if (cell.n1.ToString() == cell.n2.ToString())
563 return Noun.CreateNoun("0");
564 else
565 return Noun.CreateNoun("1");
566 }
567 }
569 private static Noun lus(Noun noun)
570 {
571 if (Noun.IsAtom(noun.ToString()))
572 {
573 Atom a = (Atom)noun;
574 int v = a.value + 1;
575 return Noun.CreateNoun(v.ToString());
576 }
577 else
578 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
579 }
581 private static Noun wut(Noun noun)
582 {
583 if (Noun.IsAtom(noun.ToString()))
584 return Noun.CreateNoun("1");
585 else
586 return Noun.CreateNoun("0");
587 }
589 private static Noun fas(Noun n1, Noun n2)
590 {
591 Noun noun = Noun.CreateNoun(n1, n2);
592 return fas(noun);
593 }
595 private static Noun fas(Noun noun)
596 {
597 if (Noun.IsAtom(noun.ToString()))
598 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
599 else
600 {
601 Cell c = (Cell)noun;
602 // 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.
603 if (Noun.IsCell(c.n1.ToString()))
604 throw new Exception("Axis must be an atom: " + c.ToString());
605 else
606 {
607 Atom a = (Atom)c.n1;
608 if (a.value == 1)
609 return c.n2;
610 else if (a.value >= 2)
611 {
612 if (!Noun.IsCell(c.n2.ToString()))
613 {
614 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
615 }
616 else
617 {
618 Cell c2 = (Cell)c.n2;
619 if (a.value == 2)
620 return c2.n1;
621 else if (a.value == 3)
622 return c2.n2;
623 else if (a.value % 2 == 0)
624 {
625 int half = a.value / 2;
626 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
627 }
628 else if (a.value % 2 == 1)
629 {
630 int half = a.value / 2;
631 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
632 }
633 else
634 {
635 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
636 }
637 }
638 }
639 }
640 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
641 }
642 }
643 }
645 class Noun
646 {
647 public Noun n1;
648 public Noun n2;
650 // takes a program, returns a pair of nouns, stringified.
651 public static Tuple<string, string> SplitCell(string program)
652 {
654 int stackCount = 0;
655 int i = 0;
656 // split the string right after the first space
657 foreach (char c in program)
658 {
659 if (IsValidChar(c))
660 {
661 if (c == '[')
662 stackCount++;
663 else if (c == ']')
664 stackCount--;
665 else if (c == ' ')
666 {
667 // if we see a space, and our stack count is at 1, then we've found our split point
668 if (stackCount == 1)
669 {
670 string a = program.Substring(1, i - 1);
671 string b = program.Substring(i + 1, program.Length - (i + 2));
673 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
674 if (!IsCell(b) && !IsAtom(b))
675 b = "[" + b + "]";
676 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
677 return tuple;
678 }
679 }
680 }
681 else
682 throw new Exception("Invalid char in cell: " + c);
683 i++;
684 }
685 throw new Exception("Invalid cell: " + program);
686 }
688 public static bool IsCell(string program)
689 {
690 // check if cell is valid, as above but make sure no space after bracket
691 // valid tokens are: space, int, [, ]
692 // from [ => [, int
693 // from int => space, ], int
694 // from ] => space, ]
695 // from space => int, [
697 // stack count must always be nonzero
698 // first and last elements must be [ and ]
700 int i = 0; // i is the stack count for brackets.
701 int counter = 0;
702 char s = '\0'; // s is the last seen character
703 // split the string right after the first space
704 foreach (char c in program)
705 {
706 if (s == '\0')
707 {
708 if (c != '[')
709 return false;
710 }
711 else if (s == '[')
712 {
713 if (!(c == '[' || IsInt(c)))
714 return false;
715 }
716 else if (IsInt(s))
717 {
718 if (!(IsInt(c) || c == ' ' || c == ']'))
719 return false;
720 }
721 else if (s == ']')
722 {
723 if (!(c == ']' || c == ' '))
724 return false;
725 }
726 else if (s == ' ')
727 {
728 if (!(c == '[' || IsInt(c)))
729 return false;
730 }
731 s = c;
732 counter++;
733 if (c == '[')
734 i++;
735 else if (c == ']')
736 i--;
737 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
738 return false;
739 }
741 // We should end with stack count of zero
742 if (i == 0)
743 return true;
744 else
745 return false;
746 }
748 public static bool IsInt(char c)
749 {
750 if (c == '0' ||
751 c == '1' ||
752 c == '2' ||
753 c == '3' ||
754 c == '4' ||
755 c == '5' ||
756 c == '6' ||
757 c == '7' ||
758 c == '8' ||
759 c == '9')
760 return true;
761 else
762 return false;
763 }
765 public static bool IsValidChar(char c)
766 {
767 if (c == ' ' ||
768 c == '[' ||
769 c == ']' ||
770 IsInt(c))
771 return true;
772 else
773 return false;
774 }
776 public static bool IsAtom(string program)
777 {
778 int i = 0;
779 if (int.TryParse(program, out i))
780 {
781 if (i >= 0)
782 return true;
783 }
784 return false;
785 }
787 public static bool IsAtom(Noun noun)
788 {
789 return IsAtom(noun.ToString());
790 }
792 public static bool IsCell(Noun noun)
793 {
794 return IsCell(noun.ToString());
795 }
797 public static Noun CreateNoun(string program)
798 {
799 if (IsAtom(program))
800 return new Atom(program);
801 else
802 return new Cell(program);
803 }
805 public static Noun CreateNoun(Noun n1, Noun n2)
806 {
807 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
808 }
810 public static Noun CreateNoun(string p1, Noun n2)
811 {
812 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
813 }
815 public static Noun CreateNoun(Noun n1, string p2)
816 {
817 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
818 }
820 public static Noun CreateNoun(string p1, string p2)
821 {
822 return CreateNoun("[" + p1 + " " + p2 + "]");
823 }
824 }
826 class Atom : Noun
827 {
828 public int value;
830 public override string ToString()
831 {
832 return value.ToString();
833 }
835 public Atom(string program)
836 {
837 if (IsAtom(program))
838 {
839 int i = 0;
840 bool result = int.TryParse(program, out i);
841 value = i;
842 }
843 else
844 throw new ArgumentException("Invalid Atom: " + program);
845 n1 = null;
846 n2 = null;
847 }
848 }
850 class Cell : Noun
851 {
852 public override string ToString()
853 {
854 return "[" + n1.ToString() + " " + n2.ToString() + "]";
855 }
857 public Cell(string program)
858 {
859 if (IsCell(program))
860 {
861 Tuple<string, string> split = SplitCell(program);
862 n1 = CreateNoun(split.Item1);
863 n2 = CreateNoun(split.Item2);
864 }
865 else
866 throw new ArgumentException("Invalid Cell: " + program);
867 }
868 }
870```
872## Groovy
874From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
876```
877@Memoized
878def i(def a) {
879 a.class in [
880 byte, Byte,
881 char, Character,
882 short, Short,
883 int, Integer,
884 long, Long,
885 BigInteger
886 ] && a >= 0
889@Memoized
890def n(def a) {
891 def r
892 n(a, { r = it })
893 r
896@TailRecursive
897def n(def a, def r) {
898 if (a in List) {
899 if (a.size() == 1) {
900 r(a[0])
901 } else if (a.size() >= 2) {
902 n(a[0], { t ->
903 n(a.size() == 2 ? a[1] : a.tail(), { h ->
904 r([t, h])
905 })
906 })
907 } else {
908 throw new IllegalStateException()
909 }
910 } else if (i(a)) {
911 r((BigInteger) a)
912 } else {
913 throw new IllegalStateException()
914 }
917@Memoized
918def wut(def a) {
919 i(a) ? 1 : 0
922@Memoized
923def lus(def a) {
924 if (wut(a) == 0) {
925 throw new IllegalStateException()
926 }
927 1 + a
930@Memoized
931def tis(def a) {
932 if (wut(a) == 1) {
933 throw new IllegalStateException()
934 }
935 a[0] == a[1] ? 0 : 1
938@Memoized
939def fas(def a) {
940 def r
941 fas(a, { r = it })
942 r
945@TailRecursive
946def fas(def a, def r) {
947 if (wut(a) == 1) {
948 throw new IllegalStateException()
949 }
950 def h = a[0]
951 if (!i(h)) {
952 throw new IllegalStateException()
953 }
954 def t = a[1]
955 if (h == 0) {
956 throw new IllegalStateException()
957 } else if (h == 1) {
958 r(t)
959 } else {
960 if (i(t)) {
961 throw new IllegalStateException()
962 }
963 if (h == 2) {
964 r(t[0])
965 } else if (h == 3) {
966 r(t[1])
967 } else {
968 fas([h.intdiv(2), t], { p ->
969 fas([2 + h.mod(2), p], { q ->
970 r(q)
971 })
972 })
973 }
974 }
977@Memoized
978def tar(def a) {
979 def r
980 tar(a, { r = it})
981 r
984@TailRecursive
985def tar(def a, def r) {
986 if (wut(a) == 1) {
987 throw new IllegalStateException()
988 }
989 def s = a[0]
990 def f = a[1]
991 if (wut(f) == 1) {
992 throw new IllegalStateException()
993 }
994 def o = f[0]
995 def v = f[1]
996 if (wut(o) == 0) {
997 tar([s, o], { p ->
998 tar([s, v], { q ->
999 r([p, q])
1000 })
1001 })
1002 } else {
1003 if (o == 0) {
1004 r(fas([v, s]))
1005 } else if (o == 1) {
1006 r(v)
1007 } else if (o == 3) {
1008 tar([s, v], {
1009 r(wut(it))
1010 })
1011 } else if (o == 4) {
1012 tar([s, v], {
1013 r(lus(it))
1014 })
1015 } else if (o == 5) {
1016 tar([s, v], {
1017 r(tis(it))
1018 })
1019 } else {
1020 if (wut(v) == 1) {
1021 throw new IllegalStateException()
1023 def x = v[0]
1024 def y = v[1]
1025 if (o == 2) {
1026 tar([s, x], { p ->
1027 tar([s, y], { q ->
1028 tar([p, q], {
1029 r(it)
1030 })
1031 })
1032 })
1033 } else if (o == 7) {
1034 tar(n([s, 2, x, 1, y]), {
1035 r(it)
1036 })
1037 } else if (o == 8) {
1038 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1039 r(it)
1040 })
1041 } else if (o == 9) {
1042 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1043 r(it)
1044 })
1045 } else if (o == 10) {
1046 if (wut(x) == 1) {
1047 tar([s, y], {
1048 r(it)
1049 })
1050 } else {
1051 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1052 r(it)
1053 })
1055 } else {
1056 if (wut(y) == 1) {
1057 throw new IllegalStateException()
1059 if (o == 6) {
1060 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1061 r(it)
1062 })
1063 } else {
1064 throw new IllegalStateException()
1070```
1072## Haskell
1074From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
1076```
1077module Language.Nock5K.Spec where
1078import Control.Monad.Instances
1080wut (a :- b) = return $ Atom 0
1081wut a = return $ Atom 1
1083lus (a :- b) = Left "+[a b]"
1084lus (Atom a) = return $ Atom (1 + a)
1086tis (a :- a') | a == a' = return $ Atom 0
1087tis (a :- b) = return $ Atom 1
1088tis a = Left "=a"
1090fas (Atom 1 :- a) = return a
1091fas (Atom 2 :- a :- b) = return a
1092fas (Atom 3 :- a :- b) = return b
1093fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
1094 fas $ Atom (2 + (a `mod` 2)) :- x
1095fas a = Left "/a"
1097tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
1098 y <- tar (a :- d)
1099 return $ x :- y
1101tar (a :- Atom 0 :- b) = fas $ b :- a
1102tar (a :- Atom 1 :- b) = return b
1103tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
1104 y <- tar (a :- c)
1105 tar $ x :- y
1106tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
1107tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
1108tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
1110tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
1111 Atom 2 :- (Atom 1 :- c :- d) :-
1112 (Atom 1 :- Atom 0) :- Atom 2 :-
1113 (Atom 1 :- Atom 2 :- Atom 3) :-
1114 (Atom 1 :- Atom 0) :- Atom 4 :-
1115 Atom 4 :- b)
1116tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
1117tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
1118 ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
1119 Atom 0 :- Atom 1) :- c)
1120tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
1121 (Atom 0 :- Atom 1) :- Atom 0 :- b)
1122tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
1123 (Atom 0 :- Atom 3) :- d)
1124tar (a :- Atom 10 :- b :- c) = tar (a :- c)
1126tar a = Left "*a"
1127```
1129## Hoon
1131```hoon
1132|= {sub/* fol/*}
1133^- *
1134?< ?=(@ fol)
1135?: ?=(^ -.fol)
1136 [$(fol -.fol) $(fol +.fol)]
1137?+ fol
1138 !!
1139 {$0 b/@}
1140 ?< =(0 b.fol)
1141 ?: =(1 b.fol) sub
1142 ?< ?=(@ sub)
1143 =+ [now=(cap b.fol) lat=(mas b.fol)]
1144 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1146 {$1 b/*}
1147 b.fol
1149 {$2 b/{^ *}}
1150 =+ ben=$(fol b.fol)
1151 $(sub -.ben, fol +.ben)
1153 {$3 b/*}
1154 =+ ben=$(fol b.fol)
1155 .?(ben)
1157 {$4 b/*}
1158 =+ ben=$(fol b.fol)
1159 ?> ?=(@ ben)
1160 +(ben)
1162 {$5 b/*}
1163 =+ ben=$(fol b.fol)
1164 ?> ?=(^ ben)
1165 =(-.ben +.ben)
1167 {$6 b/* c/* d/*}
1168 $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
1170 {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
1171 {$8 b/* c/*} $(fol =>(fol [7 [[7 [0 1] b] 0 1] c]))
1172 {$9 b/* c/*} $(fol =>(fol [7 c 2 [0 1] 0 b]))
1173 {$10 @ c/*} $(fol c.fol)
1174 {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
1176```
1178## JavaScript
1180From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1182```js
1183(function (self, factory) {
1184 'use strict'
1186 if (typeof define === 'function' && define.amd) {
1187 define([], factory)
1188 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1189 module.exports = factory()
1190 } else {
1191 self.nock = factory()
1193}(this, function () {
1194 'use strict'
1196 /**
1197 * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
1198 * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
1200 * @see http://urbit.org/docs/nock/definition/
1201 * @see https://media.urbit.org/whitepaper.pdf
1202 */
1204 var useMacros = false
1206 /*
1207 * code conventions:
1209 * `n` is a noun,
1210 * `s` is a subject noun,
1211 * `f` is a formula (or cell of formulas)
1212 */
1214 /* operators */
1216 /**
1217 * wut (?): test for atom (1) or cell (0)
1219 * ?[a b] 0
1220 * ?a 1
1221 */
1222 function wut (n) {
1223 return typeof n === 'number' ? 1 : 0
1226 /**
1227 * lus (+): increment an atom
1229 * +[a b] +[a b]
1230 * +a 1 + a
1231 */
1232 function lus (n) {
1233 if (wut(n) === 0) throw new Error('lus cell')
1234 return 1 + n
1237 /**
1238 * tis (=): test equality
1240 * =[a a] 0
1241 * =[a b] 1
1242 * =a =a
1243 */
1244 function tis (n) {
1245 if (wut(n) === 1) throw new Error('tis atom')
1246 return deepEqual(n[0], n[1]) ? 0 : 1
1249 /**
1250 * fas (/): resolve a tree address
1252 * /[1 a] a
1253 * /[2 a b] a
1254 * /[3 a b] b
1255 * /[(a + a) b] /[2 /[a b]]
1256 * /[(a + a + 1) b] /[3 /[a b]]
1257 * /a /a
1258 */
1259 function fas (addr, n) {
1260 if (n === undefined) throw new Error('invalid fas noun')
1261 if (addr === 0) throw new Error('invalid fas addr: 0')
1263 if (addr === 1) return n
1264 if (addr === 2) return n[0]
1265 if (addr === 3) return n[1]
1267 return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
1270 /* formulas */
1272 /**
1273 * slot (0): resolve a tree address
1275 * *[a 0 b] /[b a]
1276 */
1277 function slot (s, f) {
1278 var p = fas(f, s)
1280 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1282 return p
1285 /**
1286 * constant (1): return the formula regardless of subject
1288 * *[a 1 b] b
1289 */
1290 function constant (s, f) {
1291 return f
1294 /**
1295 * evaluate (2): evaluate the product of second formula against the product of the first
1297 * *[a 2 b c] *[*[a b] *[a c]]
1298 */
1299 function evaluate (s, f) {
1300 return nock(nock(s, f[0]), nock(s, f[1]))
1303 /**
1304 * cell (3): test if the product is a cell
1306 * *[a 3 b] ?*[a b]
1307 */
1308 function cell (s, f) {
1309 return wut(nock(s, f))
1312 /**
1313 * incr (4): increment the product
1315 * *[a 4 b] +*[a b]
1316 */
1317 function incr (s, f) {
1318 return lus(nock(s, f))
1321 /**
1322 * eq (5): test for equality between nouns in the product
1324 * *[a 5 b] =*[a b]
1325 */
1326 function eq (s, f) {
1327 return tis(nock(s, f))
1330 /* macro-formulas */
1332 /**
1333 * ife (6): if/then/else
1335 * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1336 */
1337 function macroIfe (s, f) {
1338 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]]]]]]]]]]])
1341 function ife (s, f) {
1342 var cond = nock(s, f[0])
1344 if (cond === 0) return nock(s, f[1][0])
1345 if (cond === 1) return nock(s, f[1][1])
1347 throw new Error('invalid ife conditional')
1350 /**
1351 * compose (7): evaluate formulas composed left-to-right
1353 * *[a 7 b c] *[a 2 b 1 c]
1354 */
1355 function macroCompose (s, f) {
1356 return nock(s, [2, [f[0], [1, f[1]]]])
1359 function compose (s, f) {
1360 // alternate form:
1361 // return nock(nock(s, f[0]), constant(s, f[1]))
1362 return nock(nock(s, f[0]), f[1])
1365 /**
1366 * extend (8): evaluate the second formula against [product of first, subject]
1368 * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
1369 */
1370 function macroExtend (s, f) {
1371 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1374 function extend (s, f) {
1375 // alternate form:
1376 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1377 return nock([nock(s, f[0]), s], f[1])
1380 /**
1381 * invoke (9): construct a core and evaluate one of it's arms against it
1383 * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
1384 */
1385 function macroInvoke (s, f) {
1386 return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
1389 function invoke (s, f) {
1390 var prod = nock(s, f[1])
1391 return nock(prod, slot(prod, f[0]))
1394 /**
1395 * hint (10): skip first formula, evaluate second
1397 * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
1398 * *[a 10 b c] *[a c]
1399 */
1400 function macroHint (s, f) {
1401 if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
1402 return nock(s, f[1])
1405 function hint (s, f) {
1406 if (wut(f[0]) === 0) {
1407 if (wut(f[0][1]) === 1) throw new Error('invalid hint')
1408 nock(s, f[0][1])
1410 return nock(s, f[1])
1413 /* indexed formula functions */
1414 var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
1415 var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
1417 /**
1418 * nock (*)
1420 * the nock function
1422 * *[a [b c] d] [*[a b c] *[a d]]
1423 * *a *a
1424 */
1425 function nock (s, f) {
1426 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
1428 var idx = f[0]
1430 if (idx > 10) throw new Error('invalid formula: ' + idx)
1432 if (useMacros) return macroFormulas[idx](s, f[1])
1434 return formulas[idx](s, f[1])
1437 /* construct a JS noun (group an array into pairs, associating right) */
1438 function assoc (x) {
1439 if (!x.length) return x
1441 if (x.length === 1) return assoc(x[0])
1443 return [assoc(x[0]), assoc(x.slice(1))]
1446 /* deep equality for arrays or primitives */
1447 function deepEqual (a, b) {
1448 if (a === b) return true
1450 if (!(Array.isArray(a) && Array.isArray(b))) return false
1451 if (a.length !== b.length) return false
1453 for (var i = 0; i < a.length; i++) {
1454 if (!deepEqual(a[i], b[i])) return false
1457 return true
1460 /* parse a hoon-serialized nock formula and construct a JS noun */
1461 function parseNoun (x) {
1462 if (Array.isArray(x)) return assoc(x)
1464 if (typeof x === 'string') {
1465 var str = x.replace(/[\."']/g, '').split(' ').join(',')
1466 return assoc(JSON.parse(str))
1469 return x
1472 function nockInterface () {
1473 var args = [].slice.call(arguments)
1474 var subject, formula, noun
1476 if (args.length === 1) {
1477 formula = parseNoun(args[0])
1478 } else if (args.length === 2) {
1479 subject = parseNoun(args[0])
1480 formula = parseNoun(args[1])
1481 } else {
1482 noun = assoc(args)
1483 subject = noun[0]
1484 formula = noun[1]
1487 if (!formula) throw new Error('formula required')
1489 if (!subject) {
1490 // !=(~)
1491 subject = [1, 0]
1494 return nock(subject, formula)
1497 return {
1498 nock: nockInterface,
1499 _nock: nock,
1500 useMacros: function (arg) {
1501 useMacros = arg === undefined || arg
1502 return this
1503 },
1504 util: {
1505 assoc: assoc,
1506 parseNoun: parseNoun,
1507 deepEqual: deepEqual
1508 },
1509 operators: {
1510 wut: wut,
1511 lus: lus,
1512 tis: tis,
1513 fas: fas
1514 },
1515 formulas: {
1516 slot: slot,
1517 constant: constant,
1518 evaluate: evaluate,
1519 cell: cell,
1520 incr: incr,
1521 eq: eq,
1522 macroIfe: macroIfe,
1523 ife: ife,
1524 macroCompose: macroCompose,
1525 compose: compose,
1526 macroExtend: macroExtend,
1527 extend: extend,
1528 macroInvoke: macroInvoke,
1529 invoke: invoke,
1530 macroHint: macroHint,
1531 hint: hint
1534}))
1535```
1537## Python
1539From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1541```py
1542#!/usr/bin/env python3
1544# []
1545def l(*lst):
1546 if len(lst) == 1:
1547 return(lst[0], 0)
1548 if len(lst) == 2:
1549 return lst
1550 else:
1551 return (lst[0], l(*lst[1:]))
1553# *
1554def nock(noun):
1555 return tar(noun)
1557# ?
1558def wut(noun):
1559 if isinstance(noun, int):
1560 return 1
1561 else:
1562 return 0
1565# +
1566def lus(noun):
1567 if isinstance(noun, int):
1568 return 1 + noun
1569 else:
1570 return noun
1573# =
1574def tis(noun):
1575 if noun[0] == noun[1]:
1576 return 0
1577 else:
1578 return 1
1581# /
1582def slot(noun):
1583 if noun[0] == 1:
1584 return noun[1]
1585 elif noun[0] == 2:
1586 return noun[1][0]
1587 elif noun[0] == 3:
1588 return noun[1][1]
1589 elif noun[0] % 2 == 0:
1590 return slot((2, slot((noun[0] // 2, noun[1]))))
1591 elif noun[0] % 2 == 1:
1592 return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
1595def tar(noun):
1596 if isinstance(noun[1][0], int):
1597 if noun[1][0] == 0:
1598 return slot((noun[1][1], noun[0]))
1599 elif noun[1][0] == 1:
1600 return noun[1][1]
1601 elif noun[1][0] == 2:
1602 return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
1603 elif noun[1][0] == 3:
1604 return wut(nock((noun[0], noun[1][1])))
1605 elif noun[1][0] == 4:
1606 return lus(nock((noun[0], noun[1][1])))
1607 elif noun[1][0] == 5:
1608 return tis(nock((noun[0], noun[1][1])))
1609 elif noun[1][0] == 6:
1610 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]))
1611 elif noun[1][0] == 7:
1612 return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
1613 elif noun[1][0] == 8:
1614 return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
1615 elif noun[1][0] == 9:
1616 return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
1617 elif noun[1][0] == 10:
1618 if isinstance(noun[1][1][0], int):
1619 return nock((noun[0], noun[1][1][1]))
1620 else:
1621 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1622 else:
1623 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1624```
1626## Ruby
1628From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1630```ruby
1631def str_to_tree(str)
1632 arr = []
1633 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1634 end
1635end
1637def max_depth(arr)
1638 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1639 ret
1640end
1642def pp(arr)
1643 depth = max_depth(arr)
1644 space = 128
1645 1.up_to(8) do |depth|
1646 space = space / 2
1647 min = 2 ** (depth - 1)
1648 max = (2 ** depth) - 1
1649 min.upto(max) { |axis|
1650 end
1652end
1654def norm(arr)
1655 return arr unless arr.is_a?(Array)
1656 while arr.size > 2
1657 size = arr.size
1658 arr[size - 2] = [ arr[size - 2], arr.pop ]
1659 end
1660 arr = arr.map { |x| norm(x) }
1661end
1663def wut(arr)
1664 arr.is_a?(Array) ? YES : NO
1665end
1667def lus(atom)
1668 raise "not an atom" unless atom.is_a?(Fixnum)
1669 atom + 1
1670end
1672def tis(arr)
1673 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1674 ( arr[0] == arr[1] ) ? YES : NO
1675end
1677def slot(axis, arr, allow_error = true)
1678 raise "axis on atom" unless arr.is_a?(Array)
1679 return arr if axis == 1
1680 return arr[0] if axis == 2
1681 return arr[1] if axis == 3
1682 return slot(2, slot(axis/2, arr)) if (axis %2) == 0
1683 return slot(3, slot(axis/2, arr))
1684end
1687def nock(arr)
1688 raise "error: nocking an atom" unless arr.is_a?(Array)
1690 oper = slot(4, arr)
1691 a = slot(2, arr)
1692 b = slot(5, arr)
1694 if oper.is_a?(Array)
1695 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1696 end
1699 case oper
1700 when 0 then
1701 slot(b,a )
1703 when 1 then
1706 when 2 then
1707 b_prime = slot(2, b)
1708 c = slot(3,b)
1709 nock( [ nock([a, b_primce]), nock([a, c]) ])
1711 when 3 then
1712 wut(nock([a, b]))
1714 when 4 then
1715 lus(nock([a, b]))
1717 when 5 then
1718 tis(nock([a, b]))
1720 when 6 then
1721 b_prime = slot(2, b)
1722 c = slot(6,b)
1723 d = slot(7,b)
1724 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1726 when 7 then
1727 b_prime = slot(2, b)
1728 c = slot(3,b)
1729 nock( norm ([a, 2, b_prime, 1, c]))
1731 when 8 then
1732 b_prime = slot(2, b)
1733 c = slot(3,b)
1734 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1736 when 9 then
1737 b_prime = slot(2, b)
1738 c = slot(3,b)
1739 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1741 when 10 then
1742 if wut(slot(2,b)) == TRUE
1743 b_prime = slot(4, b)
1744 c = slot(5, b)
1745 d = slot(3, b)
1746 c = slot(3,b)
1747 nock( norm ([a, 8, c, 7, [0, 3], d]))
1748 else
1749 b_prime = slot(2, b)
1750 c = slot(3, b)
1751 nock( norm ([a, 10, [b, c]]))
1752 end
1753 else
1754 raise "error: unknown opcode #{oper.inspect}"
1755 end
1756end
1757```
1759## Scala
1761From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
1763```scala
1764package object nnnock {
1766 sealed trait Noun;
1767 case class Atom( value : Int ) extends Noun;
1768 case class Cell( head : Noun, tail : Noun ) extends Noun;
1769 implicit def toAtom( value : Int ) : Atom = Atom( value );
1770 implicit def toInt( atom : Atom ) : Int = atom.value;
1772 def nock( a : Noun ) : Noun = *(a)
1775 object Cell {
1776 private def apply( nl : List[Noun] ) : Cell = {
1777 nl match {
1778 case a :: b :: Nil => Cell(a, b);
1779 case a :: b :: c :: Nil => Cell(a, Cell(b, c));
1780 case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
1783 def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
1786 def ?( noun : Noun ) : Noun = noun match {
1787 case _ : Cell => 0;
1788 case _ : Atom => 1;
1791 @tailrec def plus( noun : Noun ) : Noun = noun match {
1792 case a : Atom => 1 + a;
1793 case c : Cell => plus( c ); //intentional endless spin
1796 def heq( noun : Noun ) : Atom = noun match {
1797 case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
1798 case Cell( a : Cell, b : Atom ) => 1;
1799 case Cell( a : Atom, b : Cell ) => 1;
1800 case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
1801 case a : Atom => heq( a ); //intentional endless spin
1804 def /( noun : Noun ) : Noun = noun match {
1805 case Cell(Atom(1), a) => a;
1806 case Cell(Atom(2), Cell(a, b)) => a;
1807 case Cell(Atom(3), Cell(a, b)) => b;
1808 case Cell(Atom(value), b ) => {
1809 val a = value / 2;
1810 val num = if ( value % a == 0 ) 2 else 3;
1811 /(Cell(num, /(Cell(a, b))));
1813 case a => /( a ); //intentional endless spin
1817 def *( noun : Noun ) : Noun = noun match {
1818 case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
1819 case Cell( a, Cell(Atom(value), tail) ) => {
1820 (value, tail) match {
1821 case (0, b) => /( Cell(b, a) );
1822 case (1, b) => b;
1823 case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
1824 case (3, b) => ?( *( Cell(a,b) ) );
1825 case (4, b) => plus( *( Cell(a,b) ) );
1826 case (5, b) => heq( *( Cell(a,b) ) );
1827 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?
1828 case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
1829 case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
1830 case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
1831 case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
1832 case (10, Cell(b, c)) => *( Cell(a,c) );
1833 case _ => *( noun ); //intentional endless spin
1836 case a => *( a ); //intentional endless spin
1839```
1841## Scheme
1843From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
1845```scheme
1846(import (rnrs (6)))
1848(define (i a) a)
1850(define (n a r)
1851 (cond
1852 ((list? a)
1853 (let ((l (length a)))
1854 (cond
1855 ((equal? l 0) (raise 1))
1856 ((equal? l 1) (r (car a)))
1857 (else
1858 (let ((t (cond
1859 ((equal? l 2) (cadr a))
1860 (else (cdr a)))))
1861 (n (car a)
1862 (lambda (p) (n t
1863 (lambda (q) (r (cons p q)))))))))))
1864 ((fixnum? a) (r a))
1865 (else (raise 2))))
1867(define (wut a)
1868 (cond
1869 ((fixnum? a) 1)
1870 (else 0)))
1872(define (lus a)
1873 (cond
1874 ((equal? (wut a) 0) (raise 3))
1875 (else (+ 1 a))))
1877(define (tis a)
1878 (cond
1879 ((equal? (wut a) 1) (raise 4))
1880 ((equal? (car a) (cdr a)) 0)
1881 (else 1)))
1883(define (fas a r)
1884 (cond
1885 ((equal? (wut a) 1) (raise 5))
1886 (else
1887 (let ((h (car a))
1888 (t (cdr a)))
1889 (cond
1890 ((not (fixnum? h)) (raise 6))
1891 ((equal? h 0) (raise 7))
1892 ((equal? h 1) (r t))
1893 ((fixnum? t) (raise 8))
1894 ((equal? h 2) (r (car t)))
1895 ((equal? h 3) (r (cdr t)))
1896 (else
1897 (fas (cons (div h 2) t)
1898 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
1899 (lambda (q) (r q)))))))))))
1901(define (tar a r)
1902 (cond
1903 ((equal? (wut a) 1) (raise 9))
1904 (else
1905 (let ((s (car a))
1906 (f (cdr a)))
1907 (cond
1908 ((equal? (wut f) 1) (raise 10))
1909 (else
1910 (let ((o (car f))
1911 (v (cdr f)))
1912 (cond
1913 ((equal? (wut o) 0) (tar (cons s o)
1914 (lambda (p) (tar (cons s v)
1915 (lambda (q) (r (cons p q)))))))
1916 ((equal? o 0) (r (fas (cons v s) i)))
1917 ((equal? o 1) (r v))
1918 ((equal? o 3) (tar (cons s v)
1919 (lambda (p) (r (wut p)))))
1920 ((equal? o 4) (tar (cons s v)
1921 (lambda (p) (r (lus p)))))
1922 ((equal? o 5) (tar (cons s v)
1923 (lambda (p) (r (tis p)))))
1924 ((equal? (wut v) 1) (raise 11))
1925 (else
1926 (let ((x (car v))
1927 (y (cdr v)))
1928 (cond
1929 ((equal? o 2) (tar (cons s x)
1930 (lambda (p) (tar (cons s y)
1931 (lambda (q) (tar (cons p q)
1932 (lambda (u) (r u))))))))
1933 ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
1934 (lambda (p) (r p))))
1935 ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
1936 (lambda (p) (r p))))
1937 ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
1938 (lambda (p) (r p))))
1939 ((equal? o 10) (cond
1940 ((equal? (wut x) 1) (tar (cons s y)
1941 (lambda (p) (r p))))
1942 (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
1943 (lambda (p) (r p))))))
1944 ((equal? (wut y) 1) (raise 12))
1945 ((equal? o 6) (tar (n (list
1946 (list s)
1948 (list 0 1)
1950 (list 1 (list (car y)) (list (cdr y)))
1951 (list 1 0)
1953 (list 1 2 3)
1954 (list 1 0)
1957 (list x))
1958 i)
1959 (lambda (p) (r p))))
1960 (else (raise 13)))))))))))))
1961```
1963## Swift
1965```swift
1966import Foundation
1967// 1 :: A noun is an atom or a cell.
1968// 2 :: An atom is a natural number.
1969// 3 :: A cell is an ordered pair of nouns.
1970// 4
1971// 5 :: nock(a) *a
1972// 6 :: [a b c] [a [b c]]
1973// 7
1974// 8 :: ?[a b] 0
1975// 9 :: ?a 1
1976// 10 :: +[a b] +[a b]
1977// 11 :: +a 1 + a
1978// 12 :: =[a a] 0
1979// 13 :: =[a b] 1
1980// 14 :: =a =a
1981// 15
1982// 16 :: /[1 a] a
1983// 17 :: /[2 a b] a
1984// 18 :: /[3 a b] b
1985// 19 :: /[(a + a) b] /[2 /[a b]]
1986// 20 :: /[(a + a + 1) b] /[3 /[a b]]
1987// 21 :: /a /a
1988// 22
1989// 23 :: *[a [b c] d] [*[a b c] *[a d]]
1990// 24
1991// 25 :: *[a 0 b] /[b a]
1992// 26 :: *[a 1 b] b
1993// 27 :: *[a 2 b c] *[*[a b] *[a c]]
1994// 28 :: *[a 3 b] ?*[a b]
1995// 29 :: *[a 4 b] +*[a b]
1996// 30 :: *[a 5 b] =*[a b]
1997// 31
1998// 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]
1999// 33 :: *[a 7 b c] *[a 2 b 1 c]
2000// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2001// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2002// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2003// 37 :: *[a 10 b c] *[a c]
2004// 38
2005// 39 :: *a *a
2007// 1 :: A noun is an atom or a cell.
2008public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
2010 // 2 :: An atom is a natural number.
2011 public typealias ATOM = UIntMax
2013 case Atom(ATOM)
2014 // 3 :: A cell is an ordered pair of nouns.
2015 case Cell(Noun, Noun)
2016 case Invalid
2018 public static var YES: Noun { return .Atom(0) }
2019 public static var NO: Noun { return .Atom(1) }
2021 public init(_ noun: Noun) { self = noun }
2023 // 6 :: [a b c] [a [b c]]
2024 public init(_ nouns: [Noun]) {
2025 self = .Invalid
2026 if nouns.count > 0 {
2027 var reverse = nouns.reverse().generate()
2028 self = reverse.next()!
2029 while let n = reverse.next() {
2030 self = .Cell(n, self)
2035 // protocol IntegerLiteralConvertible
2036 public typealias IntegerLiteralType = ATOM
2037 public init(integerLiteral value: IntegerLiteralType) {
2038 self = .Atom(value)
2041 // protocol ArrayLiteralConvertible
2042 public typealias Element = Noun
2043 public init(arrayLiteral elements: Element...) {
2044 self = Noun(elements)
2047 // Array subscript
2048 public subscript(axis: ATOM) -> Noun {
2049 return fas(.Cell(.Atom(axis), self))
2052 // protocol Hashable
2053 public var hashValue: Int {
2054 //return self.description.hashValue
2055 switch self {
2056 case let .Atom(a):
2057 return a.hashValue
2058 case let .Cell(a, b):
2059 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2060 default:
2061 abort()
2065 // protocol CustomStringConvertible
2066 public var description: String {
2067 return describe()
2070 private func describe(depth: Int = 0) -> String {
2071 var sub = ""
2072 let next = depth+1
2073 switch self {
2074 case .Invalid:
2075 return "[%INVALID%]"
2076 case let .Atom(atom):
2077 return "\(atom)"
2078 case let .Cell(.Cell(a, b), c):
2079 sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
2080 case let .Cell(a, b):
2081 sub = "\(a.describe(next)) \(b.describe(next))"
2083 return depth == 0 ? "[\(sub)]" : sub
2087// protocol Equatable
2088public func == (left: Noun, right: Noun) -> Bool
2090 switch (left, right) {
2091 case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
2092 case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
2093 case (.Invalid, .Invalid): return true
2094 default: return false
2098public func wut(noun: Noun) -> Noun
2100 switch noun {
2101 // 8 :: ?[a b] 0
2102 case .Cell:
2103 return Noun.YES
2104 case .Atom:
2105 // 9 :: ?a 1
2106 return Noun.NO
2107 default:
2108 //return wut(noun)
2109 abort()
2113public func lus(noun: Noun) -> Noun
2115 if case let .Atom(a) = noun {
2116 // 11 :: +a 1 + a
2117 return .Atom(1+a)
2119 // 10 :: +[a b] +[a b]
2120 //return lus(noun)
2121 abort()
2124public func tis(noun: Noun) -> Noun
2126 if case let .Cell(a, b) = noun {
2127 // 12 :: =[a a] 0
2128 // 13 :: =[a b] 1
2129 return (a == b) ? Noun.YES : Noun.NO
2131 // 14 :: =a =a
2132 //return tis(noun)
2133 abort()
2136public func fas(noun: Noun) -> Noun
2138 switch noun {
2139 // 16 :: /[1 a] a
2140 case let .Cell(1, a):
2141 return a
2142 // 17 :: /[2 a b] a
2143 case let .Cell(2, .Cell(a, _)):
2144 return a
2145 // 18 :: /[3 a b] b
2146 case let .Cell(3, .Cell(_, b)):
2147 return b
2148 // 19 :: /[(a + a) b] /[2 /[a b]]
2149 // 20 :: /[(a + a + 1) b] /[3 /[a b]]
2150 case let .Cell(.Atom(axis), tree):
2151 let inner = Noun.Atom(axis / 2)
2152 let outer = Noun.Atom(2 + (axis % 2))
2153 return fas(.Cell(outer, fas(.Cell(inner, tree))))
2154 default:
2155 // 21 :: /a /a
2156 //return fas(noun)
2157 abort()
2161public func tar(noun: Noun) -> Noun
2163 switch noun {
2164 case let .Cell(a, formula):
2165 switch formula {
2166 // 23 :: *[a [b c] d] [*[a b c] *[a d]]
2167 case let .Cell(.Cell(b, c), d):
2168 return .Cell(tar([a, b, c]), tar([a, d]))
2170 // 25 :: *[a 0 b] /[b a]
2171 case let .Cell(0, b):
2172 return fas([b, a])
2174 // 26 :: *[a 1 b] b
2175 case let .Cell(1, b):
2176 return b
2178 // 27 :: *[a 2 b c] *[*[a b] *[a c]]
2179 case let .Cell(2, .Cell(b, c)):
2180 return tar([tar([a, b]), tar([a, c])])
2182 // 28 :: *[a 3 b] ?*[a b]
2183 case let .Cell(3, b):
2184 return wut(tar([a, b]))
2186 // 29 :: *[a 4 b] +*[a b]
2187 case let .Cell(4, b):
2188 return lus(tar([a, b]))
2190 // 30 :: *[a 5 b] =*[a b]
2191 case let .Cell(5, b):
2192 return tis(tar([a, b]))
2194 // 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]
2195 case let .Cell(6, .Cell(b, .Cell(c, d))):
2196 return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
2198 // 33 :: *[a 7 b c] *[a 2 b 1 c]
2199 case let .Cell(7, .Cell(b, c)):
2200 return tar([a, 2, b, 1, c])
2202 // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2203 case let .Cell(8, .Cell(b, c)):
2204 return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
2206 // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2207 case let .Cell(9, .Cell(b, c)):
2208 return tar([a, 7, c, 2, [0, 1], 0, b])
2210 // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2211 case let .Cell(10, .Cell(.Cell(_, c), d)):
2212 return tar([a, 8, c, 7, [0, 3], d])
2214 // 37 :: *[a 10 b c] *[a c]
2215 case let .Cell(10, .Cell(_, c)):
2216 return tar([a, c]);
2218 default:
2219 //return tar(noun)
2220 abort()
2222 default:
2223 //return tar(noun)
2224 abort()
2229public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2231public func dao(formula: Noun) -> Noun->Noun
2233 if let cached = nock_functions[formula] {
2234 return cached
2237 let compiler = { () -> Noun -> Noun in
2238 switch formula {
2239 case let .Cell(.Cell(b, c), d): // Distribution
2240 let (p, q) = (dao(.Cell(b, c)), dao(d))
2241 return { a in .Cell(p(a), q(a)) }
2243 case let .Cell(0, b): // Axis
2244 return { a in fas(.Cell(b, a)) }
2246 case let .Cell(1, b): // Just
2247 return { _ in b }
2249 case let .Cell(2, .Cell(b, c)): // Fire
2250 let (f, g) = (dao(b), dao(c))
2251 return { a in dao(g(a))(f(a)) }
2253 case let .Cell(3, b): // Depth
2254 let f = dao(b)
2255 return { a in wut(f(a)) }
2257 case let .Cell(4, b): // Bump
2258 let f = dao(b)
2259 return { a in lus(f(a)) }
2261 case let .Cell(5, b): // Same
2262 let f = dao(b)
2263 return { a in tis(f(a)) }
2265 case let .Cell(6, .Cell(b, .Cell(c, d))): // If
2266 let (p, q, r) = (dao(b), dao(c), dao(d))
2267 return { a in
2268 switch p(a) {
2269 case Noun.self.YES:
2270 return q(a)
2271 case Noun.self.NO:
2272 return r(a)
2273 default:
2274 return tar(.Cell(a, formula))
2278 case let .Cell(7, .Cell(b, c)): // Compose
2279 let (f, g) = (dao(b), dao(c))
2280 return { a in g(f(a)) }
2282 case let .Cell(8, .Cell(b, c)): // Push
2283 let (f, g) = (dao(b), dao(c))
2284 return { a in g(.Cell(f(a), a)) }
2286 case let .Cell(9, .Cell(b, c)): // Call
2287 let f = dao(c)
2288 return { a in
2289 let core = f(a)
2290 let arm = dao(fas(.Cell(b, core)))
2291 return arm(core)
2294 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2295 let ignore = dao(c)
2296 let f = dao(d)
2297 return { a in ignore(a); return f(a) }
2299 case let .Cell(10, .Cell(_, c)): // Hint
2300 let f = dao(c)
2301 return { a in f(a) }
2303 default:
2304 return { a in tar(.Cell(a, formula)) }
2308 let r = compiler()
2309 nock_functions[formula] = r
2310 return r
2313public func nock(n: Noun) -> Noun
2315 if case let .Cell(a, b) = n {
2316 let f = dao(b)
2317 return f(a)
2319 return nock(n)
2321```