on 514b5fc help sign in
urbit.org/content/docs/nock/implementations.md
2879 lines 86 kB history raw
1+++
2title = "Implementations"
3weight = 4
4template = "doc.html"
5+++
7We 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.):
9## Table of Contents
11- [C](#C)
13- [Clojure](#clojure)
15- [C#](#c-sharp)
17- [Groovy](#groovy)
19- [Haskell](#haskell)
21- [JavaScript](#javascript)
23- [Python](#python)
25- [Ruby](#ruby)
27- [Rust](#rust)
29- [Scala](#scala)
31- [Scheme](#scheme)
33- [Swift](#swift)
35## C Implementation
37The actual production Nock interpreter. Note gotos for tail-call elimination,
38and manual reference counting. More about the C environment can be found
39in the [runtime system documentation](/docs/vere/runtime).
40```
41/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
42*/
43static u3_noun
44_n_nock_on(u3_noun bus, u3_noun fol)
46 u3_noun hib, gal;
48 while ( 1 ) {
49 hib = u3h(fol);
50 gal = u3t(fol);
52#ifdef U3_CPU_DEBUG
53 u3R->pro.nox_d += 1;
54#endif
56 if ( c3y == u3r_du(hib) ) {
57 u3_noun poz, riv;
59 poz = _n_nock_on(u3k(bus), u3k(hib));
60 riv = _n_nock_on(bus, u3k(gal));
62 u3a_lose(fol);
63 return u3i_cell(poz, riv);
64 }
65 else switch ( hib ) {
66 default: return u3m_bail(c3__exit);
68 case 0: {
69 if ( c3n == u3r_ud(gal) ) {
70 return u3m_bail(c3__exit);
71 }
72 else {
73 u3_noun pro = u3k(u3at(gal, bus));
75 u3a_lose(bus); u3a_lose(fol);
76 return pro;
77 }
78 }
79 c3_assert(!"not reached");
81 case 1: {
82 u3_noun pro = u3k(gal);
84 u3a_lose(bus); u3a_lose(fol);
85 return pro;
86 }
87 c3_assert(!"not reached");
89 case 2: {
90 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
91 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
93 u3a_lose(fol);
94 bus = seb;
95 fol = nex;
96 continue;
97 }
98 c3_assert(!"not reached");
100 case 3: {
101 u3_noun gof, pro;
103 gof = _n_nock_on(bus, u3k(gal));
104 pro = u3r_du(gof);
106 u3a_lose(gof); u3a_lose(fol);
107 return pro;
108 }
109 c3_assert(!"not reached");
111 case 4: {
112 u3_noun gof, pro;
114 gof = _n_nock_on(bus, u3k(gal));
115 pro = u3i_vint(gof);
117 u3a_lose(fol);
118 return pro;
119 }
120 c3_assert(!"not reached");
122 case 5: {
123 u3_noun wim = _n_nock_on(bus, u3k(gal));
124 u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
126 u3a_lose(wim); u3a_lose(fol);
127 return pro;
128 }
129 c3_assert(!"not reached");
131 case 6: {
132 u3_noun b_gal, c_gal, d_gal;
134 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
135 {
136 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
137 u3_noun nex;
139 if ( 0 == tys ) {
140 nex = u3k(c_gal);
141 } else if ( 1 == tys ) {
142 nex = u3k(d_gal);
143 } else return u3m_bail(c3__exit);
145 u3a_lose(fol);
146 fol = nex;
147 continue;
148 }
149 }
150 c3_assert(!"not reached");
152 case 7: {
153 u3_noun b_gal, c_gal;
155 u3x_cell(gal, &b_gal, &c_gal);
156 {
157 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
158 u3_noun nex = u3k(c_gal);
160 u3a_lose(fol);
161 bus = bod;
162 fol = nex;
163 continue;
164 }
165 }
166 c3_assert(!"not reached");
168 case 8: {
169 u3_noun b_gal, c_gal;
171 u3x_cell(gal, &b_gal, &c_gal);
172 {
173 u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
174 u3_noun bod = u3nc(heb, bus);
175 u3_noun nex = u3k(c_gal);
177 u3a_lose(fol);
178 bus = bod;
179 fol = nex;
180 continue;
181 }
182 }
183 c3_assert(!"not reached");
185 case 9: {
186 u3_noun b_gal, c_gal;
188 u3x_cell(gal, &b_gal, &c_gal);
189 {
190 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
191 u3_noun pro;
193 u3t_off(noc_o);
194 pro = u3j_kick(seb, b_gal);
195 u3t_on(noc_o);
197 if ( u3_none != pro ) {
198 u3a_lose(fol);
199 return pro;
200 }
201 else {
202 if ( c3n == u3r_ud(b_gal) ) {
203 return u3m_bail(c3__exit);
204 }
205 else {
206 u3_noun nex = u3k(u3at(b_gal, seb));
208 u3a_lose(fol);
209 bus = seb;
210 fol = nex;
211 continue;
212 }
213 }
214 }
215 }
216 c3_assert(!"not reached");
218 case 10: {
219 u3_noun p_gal, q_gal;
221 u3x_cell(gal, &p_gal, &q_gal);
222 {
223 u3_noun zep, hod, nex;
225 if ( c3y == u3r_du(p_gal) ) {
226 u3_noun b_gal = u3h(p_gal);
227 u3_noun c_gal = u3t(p_gal);
228 u3_noun d_gal = q_gal;
230 zep = u3k(b_gal);
231 hod = _n_nock_on(u3k(bus), u3k(c_gal));
232 nex = u3k(d_gal);
233 }
234 else {
235 u3_noun b_gal = p_gal;
236 u3_noun c_gal = q_gal;
238 zep = u3k(b_gal);
239 hod = u3_nul;
240 nex = u3k(c_gal);
241 }
243 u3a_lose(fol);
244 return _n_hint(zep, hod, bus, nex);
245 }
246 }
248 case 11: {
249 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
250 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
251 u3_noun val;
253 u3t_off(noc_o);
254 val = u3m_soft_esc(ref, u3k(gof));
255 u3t_on(noc_o);
257 if ( !_(u3du(val)) ) {
258 u3m_bail(u3nt(1, gof, 0));
259 }
260 if ( !_(u3du(u3t(val))) ) {
261 //
262 // replace with proper error stack push
263 //
264 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
265 return u3m_bail(c3__exit);
266 }
267 else {
268 u3_noun pro;
270 u3z(gof);
271 u3z(fol);
272 pro = u3k(u3t(u3t(val)));
273 u3z(val);
275 return pro;
276 }
277 }
278 c3_assert(!"not reached");
279 }
280 }
282```
284## Clojure
286From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
288```
289(ns anock.core
290 (:import anock.NockException))
292(declare atom? cell? cell)
294(defn noun?
295 "A noun is an atom or a cell."
296 [noun & ns]
297 (if ns false
298 (or (atom? noun) (cell? noun))))
300(defn atom?
301 "An atom is a natural number."
302 [noun & ns]
303 (if ns false
304 (and (integer? noun) (>= noun 0))))
306(defn cell?
307 "A cell is an ordered pair of nouns."
308 [noun]
309 (cond
310 (atom? noun) false
311 (nil? noun) false
312 (not= 2 (count noun)) false
313 :else (and (noun? (first noun))
314 (noun? (second noun)))))
316(defn tis
317 "= (pronounced 'tis') tests a cell for equality."
318 [noun]
319 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
320 (let [[a b] noun]
321 (if (= a b) 0 1))))
323(defn wut
324 "? (pronounced 'wut') tests whether a noun is a cell."
325 [noun]
326 (cond
327 (atom? noun) 1
328 (cell? noun) 0
329 :else (throw (anock.NockException. "Invalid noun."))))
331(defn lus
332 "+ (pronounced 'lus') adds 1 to an atom."
333 [noun]
334 (if (atom? noun) (inc noun)
335 (throw (anock.NockException. "Can only lus atoms."))))
337(defn fas
338 "/ (pronounced 'fas') is a tree address function."
339 [noun]
340 (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
341 (let [[a b] (cell noun)]
342 (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
343 (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
344 (throw (anock.NockException. (str "Cannot fas noun: " noun))))
345 (cond
346 (= 1 a) b
347 (= 2 a) (first b)
348 (= 3 a) (second b)
349 (even? a) (fas [2 (fas [(/ a 2) b])])
350 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
352(defn tar
353 "* (pronounced 'tar') means Nock"
354 [noun]
355 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
356 (try
357 (let [noun (cell noun) [x [y z]] noun]
358 (cond
359 (cell? y) (cell (tar [x y]) (tar [x z]))
360 (zero? y) (fas [z x])
361 (= 1 y) z
362 (= 3 y) (wut (tar [x z]))
363 (= 4 y) (lus (tar [x z]))
364 (= 5 y) (tis (tar [x z]))
365 :else (let [[p q] z]
366 (cond
367 (= 2 y) (tar [(tar [x p]) (tar [x q])])
368 (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
369 [1 0] 2 [1 2 3] [1 0] 4 4 p])
370 (= 7 y) (tar [x 2 p 1 q])
371 (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
372 (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
373 (= 10 y) (if (cell? p)
374 (tar [x 8 (second p) 7 [0 3] q])
375 (tar [x q]))))))
376 (catch RuntimeException e
377 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
379(def nock tar)
381; Some convenience functions
382(defn apply* [f x]
383 (if (and (= 1 (count x)) (coll? (first x)))
384 (apply f x)
385 (f x)))
387(defn bracket
388 "[a b c] -> [a [b c]]"
389 [[a & b :as c]]
390 (let [b (vec b)]
391 (cond
392 (and (noun? a) (apply noun? b)) (vec c)
393 (apply noun? b) (apply vector (bracket a) b)
394 (noun? a) [a (apply* bracket b)]
395 :else [(bracket a) (apply* bracket b)])))
397(defn cell [& nouns]
398 (if (apply atom? nouns)
399 (throw (anock.NockException. "Cannot convert atom to cell."))
400 (apply* bracket nouns)))
401```
403## C#
405From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
407```
408using System;
409using System.Collections.Generic;
410using System.Linq;
411using System.Text;
412using System.Text.RegularExpressions;
414namespace NockInterpreter
416 class Interpreter
417 {
418 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
420 public static Noun Nock(Noun noun)
421 {
422 Start:
423 Noun cache_noun;
424 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
425 {
426 return cache_noun;
427 }
429 if (Atom.IsAtom(noun))
430 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
431 else
432 {
433 Noun subject = noun.n1;
434 if (Noun.IsCell(noun.n2))
435 {
436 Cell formula = (Cell)noun.n2;
437 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
438 {
439 Atom op = (Atom)formula.n1;
440 Noun operands = formula.n2;
442 switch (op.value)
443 {
444 case 0: // 25 :: *[a 0 b] /[b a]
445 memocache[noun.ToString()] = fas(operands, subject);
446 return memocache[noun.ToString()];
447 case 1: // 26 :: *[a 1 b] b
448 memocache[noun.ToString()] = operands;
449 return memocache[noun.ToString()];
450 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
451 if (Noun.IsCell(operands))
452 {
453 Noun a = Nock(subject, operands.n1);
454 Noun b = Nock(subject, operands.n2);
455 noun = Noun.CreateNoun(a, b);
456 goto Start;
457 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
458 }
459 throw new Exception("Atom after operand 2: " + operands.ToString());
460 case 3: // 28 :: *[a 3 b] ?*[a b]
461 memocache[noun.ToString()] = wut(Nock(subject, operands));
462 return memocache[noun.ToString()];
463 case 4: // 29 :: *[a 4 b] +*[a b]
464 memocache[noun.ToString()] = lus(Nock(subject, operands));
465 return memocache[noun.ToString()];
466 case 5: // 30 :: *[a 5 b] =*[a b]
467 memocache[noun.ToString()] = tis(Nock(subject, operands));
468 return memocache[noun.ToString()];
469 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]
470 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
471 {
472 Noun b = operands.n1;
473 Noun c = operands.n2.n1;
474 Noun d = operands.n2.n2;
475 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
476 goto Start;
477 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
478 }
479 throw new Exception("Unhandled pattern for operand 6");
480 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
481 if (Noun.IsCell(operands))
482 {
483 Noun b = operands.n1;
484 Noun c = operands.n2;
485 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
486 goto Start;
487 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
488 }
489 throw new Exception("Atom after operand 7: " + operands.ToString());
490 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
491 if (Noun.IsCell(operands))
492 {
493 Noun b = operands.n1;
494 Noun c = operands.n2;
495 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
496 goto Start;
497 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
498 }
499 throw new Exception("Atom after operand 8: " + operands.ToString());
500 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
501 if (Noun.IsCell(operands))
502 {
503 Noun b = operands.n1;
504 Noun c = operands.n2;
505 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
506 goto Start;
507 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
508 }
509 throw new Exception("Atom after operand 9: " + operands.ToString());
510 case 10:
511 if (Noun.IsCell(operands))
512 {
513 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
514 {
515 Noun b = operands.n1.n1;
516 Noun c = operands.n1.n2;
517 Noun d = operands.n2;
518 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
519 goto Start;
520 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
521 }
522 else // 37 :: *[a 10 b c] *[a c]
523 {
524 Noun c = operands.n2;
525 noun = Noun.CreateNoun(subject, c);
526 goto Start;
527 // return Nock(subject, c);
528 }
529 }
530 throw new Exception("Atom after operand 10: " + operands.ToString());
531 default:
532 throw new Exception("Unknown operand: " + op.value);
533 }
534 }
535 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
536 {
537 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
538 return memocache[noun.ToString()];
539 }
540 }
541 }
542 throw new Exception("Unhandled pattern");
543 }
545 public static Noun Nock(string program)
546 {
547 Noun noun = Noun.CreateNoun(program);
548 return Nock(noun);
549 }
551 public static Noun Nock(Noun n1, Noun n2)
552 {
553 Noun noun = Noun.CreateNoun(n1, n2);
554 return Nock(noun);
555 }
557 private static Noun tis(Noun noun)
558 {
559 if (Noun.IsAtom(noun.ToString()))
560 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
561 else
562 {
563 Cell cell = (Cell)noun;
565 if (cell.n1.ToString() == cell.n2.ToString())
566 return Noun.CreateNoun("0");
567 else
568 return Noun.CreateNoun("1");
569 }
570 }
572 private static Noun lus(Noun noun)
573 {
574 if (Noun.IsAtom(noun.ToString()))
575 {
576 Atom a = (Atom)noun;
577 int v = a.value + 1;
578 return Noun.CreateNoun(v.ToString());
579 }
580 else
581 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
582 }
584 private static Noun wut(Noun noun)
585 {
586 if (Noun.IsAtom(noun.ToString()))
587 return Noun.CreateNoun("1");
588 else
589 return Noun.CreateNoun("0");
590 }
592 private static Noun fas(Noun n1, Noun n2)
593 {
594 Noun noun = Noun.CreateNoun(n1, n2);
595 return fas(noun);
596 }
598 private static Noun fas(Noun noun)
599 {
600 if (Noun.IsAtom(noun.ToString()))
601 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
602 else
603 {
604 Cell c = (Cell)noun;
605 // 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.
606 if (Noun.IsCell(c.n1.ToString()))
607 throw new Exception("Axis must be an atom: " + c.ToString());
608 else
609 {
610 Atom a = (Atom)c.n1;
611 if (a.value == 1)
612 return c.n2;
613 else if (a.value >= 2)
614 {
615 if (!Noun.IsCell(c.n2.ToString()))
616 {
617 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
618 }
619 else
620 {
621 Cell c2 = (Cell)c.n2;
622 if (a.value == 2)
623 return c2.n1;
624 else if (a.value == 3)
625 return c2.n2;
626 else if (a.value % 2 == 0)
627 {
628 int half = a.value / 2;
629 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
630 }
631 else if (a.value % 2 == 1)
632 {
633 int half = a.value / 2;
634 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
635 }
636 else
637 {
638 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
639 }
640 }
641 }
642 }
643 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
644 }
645 }
646 }
648 class Noun
649 {
650 public Noun n1;
651 public Noun n2;
653 // takes a program, returns a pair of nouns, stringified.
654 public static Tuple<string, string> SplitCell(string program)
655 {
657 int stackCount = 0;
658 int i = 0;
659 // split the string right after the first space
660 foreach (char c in program)
661 {
662 if (IsValidChar(c))
663 {
664 if (c == '[')
665 stackCount++;
666 else if (c == ']')
667 stackCount--;
668 else if (c == ' ')
669 {
670 // if we see a space, and our stack count is at 1, then we've found our split point
671 if (stackCount == 1)
672 {
673 string a = program.Substring(1, i - 1);
674 string b = program.Substring(i + 1, program.Length - (i + 2));
676 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
677 if (!IsCell(b) && !IsAtom(b))
678 b = "[" + b + "]";
679 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
680 return tuple;
681 }
682 }
683 }
684 else
685 throw new Exception("Invalid char in cell: " + c);
686 i++;
687 }
688 throw new Exception("Invalid cell: " + program);
689 }
691 public static bool IsCell(string program)
692 {
693 // check if cell is valid, as above but make sure no space after bracket
694 // valid tokens are: space, int, [, ]
695 // from [ => [, int
696 // from int => space, ], int
697 // from ] => space, ]
698 // from space => int, [
700 // stack count must always be nonzero
701 // first and last elements must be [ and ]
703 int i = 0; // i is the stack count for brackets.
704 int counter = 0;
705 char s = '\0'; // s is the last seen character
706 // split the string right after the first space
707 foreach (char c in program)
708 {
709 if (s == '\0')
710 {
711 if (c != '[')
712 return false;
713 }
714 else if (s == '[')
715 {
716 if (!(c == '[' || IsInt(c)))
717 return false;
718 }
719 else if (IsInt(s))
720 {
721 if (!(IsInt(c) || c == ' ' || c == ']'))
722 return false;
723 }
724 else if (s == ']')
725 {
726 if (!(c == ']' || c == ' '))
727 return false;
728 }
729 else if (s == ' ')
730 {
731 if (!(c == '[' || IsInt(c)))
732 return false;
733 }
734 s = c;
735 counter++;
736 if (c == '[')
737 i++;
738 else if (c == ']')
739 i--;
740 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
741 return false;
742 }
744 // We should end with stack count of zero
745 if (i == 0)
746 return true;
747 else
748 return false;
749 }
751 public static bool IsInt(char c)
752 {
753 if (c == '0' ||
754 c == '1' ||
755 c == '2' ||
756 c == '3' ||
757 c == '4' ||
758 c == '5' ||
759 c == '6' ||
760 c == '7' ||
761 c == '8' ||
762 c == '9')
763 return true;
764 else
765 return false;
766 }
768 public static bool IsValidChar(char c)
769 {
770 if (c == ' ' ||
771 c == '[' ||
772 c == ']' ||
773 IsInt(c))
774 return true;
775 else
776 return false;
777 }
779 public static bool IsAtom(string program)
780 {
781 int i = 0;
782 if (int.TryParse(program, out i))
783 {
784 if (i >= 0)
785 return true;
786 }
787 return false;
788 }
790 public static bool IsAtom(Noun noun)
791 {
792 return IsAtom(noun.ToString());
793 }
795 public static bool IsCell(Noun noun)
796 {
797 return IsCell(noun.ToString());
798 }
800 public static Noun CreateNoun(string program)
801 {
802 if (IsAtom(program))
803 return new Atom(program);
804 else
805 return new Cell(program);
806 }
808 public static Noun CreateNoun(Noun n1, Noun n2)
809 {
810 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
811 }
813 public static Noun CreateNoun(string p1, Noun n2)
814 {
815 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
816 }
818 public static Noun CreateNoun(Noun n1, string p2)
819 {
820 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
821 }
823 public static Noun CreateNoun(string p1, string p2)
824 {
825 return CreateNoun("[" + p1 + " " + p2 + "]");
826 }
827 }
829 class Atom : Noun
830 {
831 public int value;
833 public override string ToString()
834 {
835 return value.ToString();
836 }
838 public Atom(string program)
839 {
840 if (IsAtom(program))
841 {
842 int i = 0;
843 bool result = int.TryParse(program, out i);
844 value = i;
845 }
846 else
847 throw new ArgumentException("Invalid Atom: " + program);
848 n1 = null;
849 n2 = null;
850 }
851 }
853 class Cell : Noun
854 {
855 public override string ToString()
856 {
857 return "[" + n1.ToString() + " " + n2.ToString() + "]";
858 }
860 public Cell(string program)
861 {
862 if (IsCell(program))
863 {
864 Tuple<string, string> split = SplitCell(program);
865 n1 = CreateNoun(split.Item1);
866 n2 = CreateNoun(split.Item2);
867 }
868 else
869 throw new ArgumentException("Invalid Cell: " + program);
870 }
871 }
873```
875## Groovy
877From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
879```
880@Memoized
881def i(def a) {
882 a.class in [
883 byte, Byte,
884 char, Character,
885 short, Short,
886 int, Integer,
887 long, Long,
888 BigInteger
889 ] && a >= 0
892@Memoized
893def n(def a) {
894 def r
895 n(a, { r = it })
896 r
899@TailRecursive
900def n(def a, def r) {
901 if (a in List) {
902 if (a.size() == 1) {
903 r(a[0])
904 } else if (a.size() >= 2) {
905 n(a[0], { t ->
906 n(a.size() == 2 ? a[1] : a.tail(), { h ->
907 r([t, h])
908 })
909 })
910 } else {
911 throw new IllegalStateException()
912 }
913 } else if (i(a)) {
914 r((BigInteger) a)
915 } else {
916 throw new IllegalStateException()
917 }
920@Memoized
921def wut(def a) {
922 i(a) ? 1 : 0
925@Memoized
926def lus(def a) {
927 if (wut(a) == 0) {
928 throw new IllegalStateException()
929 }
930 1 + a
933@Memoized
934def tis(def a) {
935 if (wut(a) == 1) {
936 throw new IllegalStateException()
937 }
938 a[0] == a[1] ? 0 : 1
941@Memoized
942def fas(def a) {
943 def r
944 fas(a, { r = it })
945 r
948@TailRecursive
949def fas(def a, def r) {
950 if (wut(a) == 1) {
951 throw new IllegalStateException()
952 }
953 def h = a[0]
954 if (!i(h)) {
955 throw new IllegalStateException()
956 }
957 def t = a[1]
958 if (h == 0) {
959 throw new IllegalStateException()
960 } else if (h == 1) {
961 r(t)
962 } else {
963 if (i(t)) {
964 throw new IllegalStateException()
965 }
966 if (h == 2) {
967 r(t[0])
968 } else if (h == 3) {
969 r(t[1])
970 } else {
971 fas([h.intdiv(2), t], { p ->
972 fas([2 + h.mod(2), p], { q ->
973 r(q)
974 })
975 })
976 }
977 }
980@Memoized
981def tar(def a) {
982 def r
983 tar(a, { r = it})
984 r
987@TailRecursive
988def tar(def a, def r) {
989 if (wut(a) == 1) {
990 throw new IllegalStateException()
991 }
992 def s = a[0]
993 def f = a[1]
994 if (wut(f) == 1) {
995 throw new IllegalStateException()
996 }
997 def o = f[0]
998 def v = f[1]
999 if (wut(o) == 0) {
1000 tar([s, o], { p ->
1001 tar([s, v], { q ->
1002 r([p, q])
1003 })
1004 })
1005 } else {
1006 if (o == 0) {
1007 r(fas([v, s]))
1008 } else if (o == 1) {
1009 r(v)
1010 } else if (o == 3) {
1011 tar([s, v], {
1012 r(wut(it))
1013 })
1014 } else if (o == 4) {
1015 tar([s, v], {
1016 r(lus(it))
1017 })
1018 } else if (o == 5) {
1019 tar([s, v], {
1020 r(tis(it))
1021 })
1022 } else {
1023 if (wut(v) == 1) {
1024 throw new IllegalStateException()
1026 def x = v[0]
1027 def y = v[1]
1028 if (o == 2) {
1029 tar([s, x], { p ->
1030 tar([s, y], { q ->
1031 tar([p, q], {
1032 r(it)
1033 })
1034 })
1035 })
1036 } else if (o == 7) {
1037 tar(n([s, 2, x, 1, y]), {
1038 r(it)
1039 })
1040 } else if (o == 8) {
1041 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1042 r(it)
1043 })
1044 } else if (o == 9) {
1045 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1046 r(it)
1047 })
1048 } else if (o == 10) {
1049 if (wut(x) == 1) {
1050 tar([s, y], {
1051 r(it)
1052 })
1053 } else {
1054 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1055 r(it)
1056 })
1058 } else {
1059 if (wut(y) == 1) {
1060 throw new IllegalStateException()
1062 if (o == 6) {
1063 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1064 r(it)
1065 })
1066 } else {
1067 throw new IllegalStateException()
1073```
1075## Haskell
1077From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
1079```
1080module Language.Nock5K.Spec where
1081import Control.Monad.Instances
1083wut (a :- b) = return $ Atom 0
1084wut a = return $ Atom 1
1086lus (a :- b) = Left "+[a b]"
1087lus (Atom a) = return $ Atom (1 + a)
1089tis (a :- a') | a == a' = return $ Atom 0
1090tis (a :- b) = return $ Atom 1
1091tis a = Left "=a"
1093fas (Atom 1 :- a) = return a
1094fas (Atom 2 :- a :- b) = return a
1095fas (Atom 3 :- a :- b) = return b
1096fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
1097 fas $ Atom (2 + (a `mod` 2)) :- x
1098fas a = Left "/a"
1100tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
1101 y <- tar (a :- d)
1102 return $ x :- y
1104tar (a :- Atom 0 :- b) = fas $ b :- a
1105tar (a :- Atom 1 :- b) = return b
1106tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
1107 y <- tar (a :- c)
1108 tar $ x :- y
1109tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
1110tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
1111tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
1113tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
1114 Atom 2 :- (Atom 1 :- c :- d) :-
1115 (Atom 1 :- Atom 0) :- Atom 2 :-
1116 (Atom 1 :- Atom 2 :- Atom 3) :-
1117 (Atom 1 :- Atom 0) :- Atom 4 :-
1118 Atom 4 :- b)
1119tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
1120tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
1121 ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
1122 Atom 0 :- Atom 1) :- c)
1123tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
1124 (Atom 0 :- Atom 1) :- Atom 0 :- b)
1125tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
1126 (Atom 0 :- Atom 3) :- d)
1127tar (a :- Atom 10 :- b :- c) = tar (a :- c)
1129tar a = Left "*a"
1130```
1132## Hoon
1134```hoon
1135|= {sub/* fol/*}
1136^- *
1137?< ?=(@ fol)
1138?: ?=(^ -.fol)
1139 [$(fol -.fol) $(fol +.fol)]
1140?+ fol
1141 !!
1142 {$0 b/@}
1143 ?< =(0 b.fol)
1144 ?: =(1 b.fol) sub
1145 ?< ?=(@ sub)
1146 =+ [now=(cap b.fol) lat=(mas b.fol)]
1147 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1149 {$1 b/*}
1150 b.fol
1152 {$2 b/{^ *}}
1153 =+ ben=$(fol b.fol)
1154 $(sub -.ben, fol +.ben)
1156 {$3 b/*}
1157 =+ ben=$(fol b.fol)
1158 .?(ben)
1160 {$4 b/*}
1161 =+ ben=$(fol b.fol)
1162 ?> ?=(@ ben)
1163 +(ben)
1165 {$5 b/*}
1166 =+ ben=$(fol b.fol)
1167 ?> ?=(^ ben)
1168 =(-.ben +.ben)
1170 {$6 b/* c/* d/*}
1171 $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
1173 {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
1174 {$8 b/* c/*} $(fol =>(fol [7 [[7 [0 1] b] 0 1] c]))
1175 {$9 b/* c/*} $(fol =>(fol [7 c 2 [0 1] 0 b]))
1176 {$10 @ c/*} $(fol c.fol)
1177 {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
1179```
1181## JavaScript
1183From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1185```js
1186(function (self, factory) {
1187 'use strict'
1189 if (typeof define === 'function' && define.amd) {
1190 define([], factory)
1191 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1192 module.exports = factory()
1193 } else {
1194 self.nock = factory()
1196}(this, function () {
1197 'use strict'
1199 /**
1200 * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
1201 * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
1203 * @see http://urbit.org/docs/nock/definition/
1204 * @see https://media.urbit.org/whitepaper.pdf
1205 */
1207 var useMacros = false
1209 /*
1210 * code conventions:
1212 * `n` is a noun,
1213 * `s` is a subject noun,
1214 * `f` is a formula (or cell of formulas)
1215 */
1217 /* operators */
1219 /**
1220 * wut (?): test for atom (1) or cell (0)
1222 * ?[a b] 0
1223 * ?a 1
1224 */
1225 function wut (n) {
1226 return typeof n === 'number' ? 1 : 0
1229 /**
1230 * lus (+): increment an atom
1232 * +[a b] +[a b]
1233 * +a 1 + a
1234 */
1235 function lus (n) {
1236 if (wut(n) === 0) throw new Error('lus cell')
1237 return 1 + n
1240 /**
1241 * tis (=): test equality
1243 * =[a a] 0
1244 * =[a b] 1
1245 * =a =a
1246 */
1247 function tis (n) {
1248 if (wut(n) === 1) throw new Error('tis atom')
1249 return deepEqual(n[0], n[1]) ? 0 : 1
1252 /**
1253 * fas (/): resolve a tree address
1255 * /[1 a] a
1256 * /[2 a b] a
1257 * /[3 a b] b
1258 * /[(a + a) b] /[2 /[a b]]
1259 * /[(a + a + 1) b] /[3 /[a b]]
1260 * /a /a
1261 */
1262 function fas (addr, n) {
1263 if (n === undefined) throw new Error('invalid fas noun')
1264 if (addr === 0) throw new Error('invalid fas addr: 0')
1266 if (addr === 1) return n
1267 if (addr === 2) return n[0]
1268 if (addr === 3) return n[1]
1270 return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
1273 /* formulas */
1275 /**
1276 * slot (0): resolve a tree address
1278 * *[a 0 b] /[b a]
1279 */
1280 function slot (s, f) {
1281 var p = fas(f, s)
1283 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1285 return p
1288 /**
1289 * constant (1): return the formula regardless of subject
1291 * *[a 1 b] b
1292 */
1293 function constant (s, f) {
1294 return f
1297 /**
1298 * evaluate (2): evaluate the product of second formula against the product of the first
1300 * *[a 2 b c] *[*[a b] *[a c]]
1301 */
1302 function evaluate (s, f) {
1303 return nock(nock(s, f[0]), nock(s, f[1]))
1306 /**
1307 * cell (3): test if the product is a cell
1309 * *[a 3 b] ?*[a b]
1310 */
1311 function cell (s, f) {
1312 return wut(nock(s, f))
1315 /**
1316 * incr (4): increment the product
1318 * *[a 4 b] +*[a b]
1319 */
1320 function incr (s, f) {
1321 return lus(nock(s, f))
1324 /**
1325 * eq (5): test for equality between nouns in the product
1327 * *[a 5 b] =*[a b]
1328 */
1329 function eq (s, f) {
1330 return tis(nock(s, f))
1333 /* macro-formulas */
1335 /**
1336 * ife (6): if/then/else
1338 * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1339 */
1340 function macroIfe (s, f) {
1341 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]]]]]]]]]]])
1344 function ife (s, f) {
1345 var cond = nock(s, f[0])
1347 if (cond === 0) return nock(s, f[1][0])
1348 if (cond === 1) return nock(s, f[1][1])
1350 throw new Error('invalid ife conditional')
1353 /**
1354 * compose (7): evaluate formulas composed left-to-right
1356 * *[a 7 b c] *[a 2 b 1 c]
1357 */
1358 function macroCompose (s, f) {
1359 return nock(s, [2, [f[0], [1, f[1]]]])
1362 function compose (s, f) {
1363 // alternate form:
1364 // return nock(nock(s, f[0]), constant(s, f[1]))
1365 return nock(nock(s, f[0]), f[1])
1368 /**
1369 * extend (8): evaluate the second formula against [product of first, subject]
1371 * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
1372 */
1373 function macroExtend (s, f) {
1374 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1377 function extend (s, f) {
1378 // alternate form:
1379 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1380 return nock([nock(s, f[0]), s], f[1])
1383 /**
1384 * invoke (9): construct a core and evaluate one of its arms against it
1386 * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
1387 */
1388 function macroInvoke (s, f) {
1389 return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
1392 function invoke (s, f) {
1393 var prod = nock(s, f[1])
1394 return nock(prod, slot(prod, f[0]))
1397 /**
1398 * hint (10): skip first formula, evaluate second
1400 * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
1401 * *[a 10 b c] *[a c]
1402 */
1403 function macroHint (s, f) {
1404 if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
1405 return nock(s, f[1])
1408 function hint (s, f) {
1409 if (wut(f[0]) === 0) {
1410 if (wut(f[0][1]) === 1) throw new Error('invalid hint')
1411 nock(s, f[0][1])
1413 return nock(s, f[1])
1416 /* indexed formula functions */
1417 var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
1418 var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
1420 /**
1421 * nock (*)
1423 * the nock function
1425 * *[a [b c] d] [*[a b c] *[a d]]
1426 * *a *a
1427 */
1428 function nock (s, f) {
1429 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
1431 var idx = f[0]
1433 if (idx > 10) throw new Error('invalid formula: ' + idx)
1435 if (useMacros) return macroFormulas[idx](s, f[1])
1437 return formulas[idx](s, f[1])
1440 /* construct a JS noun (group an array into pairs, associating right) */
1441 function assoc (x) {
1442 if (!x.length) return x
1444 if (x.length === 1) return assoc(x[0])
1446 return [assoc(x[0]), assoc(x.slice(1))]
1449 /* deep equality for arrays or primitives */
1450 function deepEqual (a, b) {
1451 if (a === b) return true
1453 if (!(Array.isArray(a) && Array.isArray(b))) return false
1454 if (a.length !== b.length) return false
1456 for (var i = 0; i < a.length; i++) {
1457 if (!deepEqual(a[i], b[i])) return false
1460 return true
1463 /* parse a hoon-serialized nock formula and construct a JS noun */
1464 function parseNoun (x) {
1465 if (Array.isArray(x)) return assoc(x)
1467 if (typeof x === 'string') {
1468 var str = x.replace(/[\."']/g, '').split(' ').join(',')
1469 return assoc(JSON.parse(str))
1472 return x
1475 function nockInterface () {
1476 var args = [].slice.call(arguments)
1477 var subject, formula, noun
1479 if (args.length === 1) {
1480 formula = parseNoun(args[0])
1481 } else if (args.length === 2) {
1482 subject = parseNoun(args[0])
1483 formula = parseNoun(args[1])
1484 } else {
1485 noun = assoc(args)
1486 subject = noun[0]
1487 formula = noun[1]
1490 if (!formula) throw new Error('formula required')
1492 if (!subject) {
1493 // !=(~)
1494 subject = [1, 0]
1497 return nock(subject, formula)
1500 return {
1501 nock: nockInterface,
1502 _nock: nock,
1503 useMacros: function (arg) {
1504 useMacros = arg === undefined || arg
1505 return this
1506 },
1507 util: {
1508 assoc: assoc,
1509 parseNoun: parseNoun,
1510 deepEqual: deepEqual
1511 },
1512 operators: {
1513 wut: wut,
1514 lus: lus,
1515 tis: tis,
1516 fas: fas
1517 },
1518 formulas: {
1519 slot: slot,
1520 constant: constant,
1521 evaluate: evaluate,
1522 cell: cell,
1523 incr: incr,
1524 eq: eq,
1525 macroIfe: macroIfe,
1526 ife: ife,
1527 macroCompose: macroCompose,
1528 compose: compose,
1529 macroExtend: macroExtend,
1530 extend: extend,
1531 macroInvoke: macroInvoke,
1532 invoke: invoke,
1533 macroHint: macroHint,
1534 hint: hint
1537}))
1538```
1540## Python
1542From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1544```py
1545#!/usr/bin/env python3
1547# []
1548def l(*lst):
1549 if len(lst) == 1:
1550 return(lst[0], 0)
1551 if len(lst) == 2:
1552 return lst
1553 else:
1554 return (lst[0], l(*lst[1:]))
1556# *
1557def nock(noun):
1558 return tar(noun)
1560# ?
1561def wut(noun):
1562 if isinstance(noun, int):
1563 return 1
1564 else:
1565 return 0
1568# +
1569def lus(noun):
1570 if isinstance(noun, int):
1571 return 1 + noun
1572 else:
1573 return noun
1576# =
1577def tis(noun):
1578 if noun[0] == noun[1]:
1579 return 0
1580 else:
1581 return 1
1584# /
1585def slot(noun):
1586 if noun[0] == 1:
1587 return noun[1]
1588 elif noun[0] == 2:
1589 return noun[1][0]
1590 elif noun[0] == 3:
1591 return noun[1][1]
1592 elif noun[0] % 2 == 0:
1593 return slot((2, slot((noun[0] // 2, noun[1]))))
1594 elif noun[0] % 2 == 1:
1595 return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
1598def tar(noun):
1599 if isinstance(noun[1][0], int):
1600 if noun[1][0] == 0:
1601 return slot((noun[1][1], noun[0]))
1602 elif noun[1][0] == 1:
1603 return noun[1][1]
1604 elif noun[1][0] == 2:
1605 return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
1606 elif noun[1][0] == 3:
1607 return wut(nock((noun[0], noun[1][1])))
1608 elif noun[1][0] == 4:
1609 return lus(nock((noun[0], noun[1][1])))
1610 elif noun[1][0] == 5:
1611 return tis(nock((noun[0], noun[1][1])))
1612 elif noun[1][0] == 6:
1613 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]))
1614 elif noun[1][0] == 7:
1615 return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
1616 elif noun[1][0] == 8:
1617 return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
1618 elif noun[1][0] == 9:
1619 return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
1620 elif noun[1][0] == 10:
1621 if isinstance(noun[1][1][0], int):
1622 return nock((noun[0], noun[1][1][1]))
1623 else:
1624 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1625 else:
1626 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1627```
1629## Ruby
1631From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1633```ruby
1634def str_to_tree(str)
1635 arr = []
1636 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1637 end
1638end
1640def max_depth(arr)
1641 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1642 ret
1643end
1645def pp(arr)
1646 depth = max_depth(arr)
1647 space = 128
1648 1.up_to(8) do |depth|
1649 space = space / 2
1650 min = 2 ** (depth - 1)
1651 max = (2 ** depth) - 1
1652 min.upto(max) { |axis|
1653 end
1655end
1657def norm(arr)
1658 return arr unless arr.is_a?(Array)
1659 while arr.size > 2
1660 size = arr.size
1661 arr[size - 2] = [ arr[size - 2], arr.pop ]
1662 end
1663 arr = arr.map { |x| norm(x) }
1664end
1666def wut(arr)
1667 arr.is_a?(Array) ? YES : NO
1668end
1670def lus(atom)
1671 raise "not an atom" unless atom.is_a?(Fixnum)
1672 atom + 1
1673end
1675def tis(arr)
1676 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1677 ( arr[0] == arr[1] ) ? YES : NO
1678end
1680def slot(axis, arr, allow_error = true)
1681 raise "axis on atom" unless arr.is_a?(Array)
1682 return arr if axis == 1
1683 return arr[0] if axis == 2
1684 return arr[1] if axis == 3
1685 return slot(2, slot(axis/2, arr)) if (axis %2) == 0
1686 return slot(3, slot(axis/2, arr))
1687end
1690def nock(arr)
1691 raise "error: nocking an atom" unless arr.is_a?(Array)
1693 oper = slot(4, arr)
1694 a = slot(2, arr)
1695 b = slot(5, arr)
1697 if oper.is_a?(Array)
1698 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1699 end
1702 case oper
1703 when 0 then
1704 slot(b,a )
1706 when 1 then
1709 when 2 then
1710 b_prime = slot(2, b)
1711 c = slot(3,b)
1712 nock( [ nock([a, b_primce]), nock([a, c]) ])
1714 when 3 then
1715 wut(nock([a, b]))
1717 when 4 then
1718 lus(nock([a, b]))
1720 when 5 then
1721 tis(nock([a, b]))
1723 when 6 then
1724 b_prime = slot(2, b)
1725 c = slot(6,b)
1726 d = slot(7,b)
1727 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1729 when 7 then
1730 b_prime = slot(2, b)
1731 c = slot(3,b)
1732 nock( norm ([a, 2, b_prime, 1, c]))
1734 when 8 then
1735 b_prime = slot(2, b)
1736 c = slot(3,b)
1737 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1739 when 9 then
1740 b_prime = slot(2, b)
1741 c = slot(3,b)
1742 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1744 when 10 then
1745 if wut(slot(2,b)) == TRUE
1746 b_prime = slot(4, b)
1747 c = slot(5, b)
1748 d = slot(3, b)
1749 c = slot(3,b)
1750 nock( norm ([a, 8, c, 7, [0, 3], d]))
1751 else
1752 b_prime = slot(2, b)
1753 c = slot(3, b)
1754 nock( norm ([a, 10, [b, c]]))
1755 end
1756 else
1757 raise "error: unknown opcode #{oper.inspect}"
1758 end
1759end
1760```
1762## Rust
1764From [Peter McEvoy](https://github.com/mcevoypeter/nock/tree/main/src):
1766```rust
1767#![allow(unused_parens)]
1769use std::{error, fmt};
1771#[derive(Debug)]
1772enum Noun {
1773 Atom(Atom),
1774 Cell(Cell),
1777impl Clone for Noun {
1778 fn clone(&self) -> Self {
1779 match self {
1780 Noun::Atom(a) => Noun::Atom(Atom(a.0)),
1781 Noun::Cell(c) => Noun::Cell(Cell {
1782 h: c.h.clone(),
1783 t: c.t.clone(),
1784 }),
1789impl PartialEq for Noun {
1790 fn eq(&self, other: &Self) -> bool {
1791 if let (Noun::Atom(lh), Noun::Atom(rh)) = (&*self, &*other) {
1792 lh == rh
1793 } else if let (Noun::Cell(lh), Noun::Cell(rh)) = (&*self, &*other) {
1794 lh == rh
1795 } else {
1796 false
1801impl fmt::Display for Noun {
1802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1803 match self {
1804 Noun::Atom(a) => {
1805 write!(f, "{}", a.0)
1807 Noun::Cell(ref c) => {
1808 write!(f, "[{} {}]", c.h, c.t)
1814impl Noun {
1815 fn from_loobean(loob: Loobean) -> Self {
1816 match loob {
1817 Loobean::Yes => Noun::Atom(Atom(0)),
1818 Loobean::No => Noun::Atom(Atom(1)),
1822 fn into_box(self) -> Box<Self> {
1823 Box::new(self)
1827#[derive(Clone, Debug, PartialEq)]
1828struct Atom(u64);
1830#[derive(Debug)]
1831pub struct Cell {
1832 h: Box<Noun>,
1833 t: Box<Noun>,
1836impl Clone for Cell {
1837 fn clone(&self) -> Self {
1838 Cell {
1839 h: self.h.clone(),
1840 t: self.t.clone(),
1845impl PartialEq for Cell {
1846 fn eq(&self, other: &Self) -> bool {
1847 if let (Noun::Atom(lh_h), Noun::Atom(rh_h)) = (&*self.h, &*other.h) {
1848 lh_h == rh_h && *self.t == *other.t
1849 } else if let (Noun::Cell(lh_h), Noun::Cell(rh_h)) = (&*self.h, &*other.h) {
1850 Self::eq(lh_h, rh_h) && *self.t == *other.t
1851 } else {
1852 false
1857#[derive(Debug, PartialEq)]
1858enum Loobean {
1859 Yes,
1860 No,
1863impl Loobean {
1864 fn from_boolean(b: bool) -> Self {
1865 if b {
1866 Loobean::Yes
1867 } else {
1868 Loobean::No
1873#[derive(Debug)]
1874struct Error {
1875 msg: String,
1878impl fmt::Display for Error {
1879 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1880 write!(f, "{}", self.msg)
1884impl error::Error for Error {}
1886trait Wut {
1887 fn wut(&self) -> Loobean;
1890impl Wut for Atom {
1891 fn wut(&self) -> Loobean {
1892 Loobean::No
1896impl Wut for Cell {
1897 fn wut(&self) -> Loobean {
1898 Loobean::Yes
1902trait Lus {
1903 fn lus(self) -> Atom;
1906impl Lus for Atom {
1907 fn lus(self) -> Atom {
1908 Atom(1 + self.0)
1912trait Tis {
1913 fn tis(&self) -> Loobean;
1916impl Tis for Cell {
1917 fn tis(&self) -> Loobean {
1918 Loobean::from_boolean(self.h == self.t)
1922trait Fas {
1923 fn fas(self) -> Result<Noun, Error>;
1926impl Fas for Cell {
1927 fn fas(self) -> Result<Noun, Error> {
1928 let mut s = self;
1929 loop {
1930 match *s.h {
1931 Noun::Atom(Atom(0)) => {
1932 break Err(Error {
1933 msg: "/[0 a] cannot be evaluated".to_string(),
1934 })
1936 Noun::Atom(Atom(1)) => break Ok(*s.t),
1937 Noun::Atom(Atom(2)) => {
1938 break {
1939 if let Noun::Cell(t) = *s.t {
1940 Ok(*t.h)
1941 } else {
1942 Err(Error {
1943 msg: "/[2 a] cannot be evaluated when a is an atom".to_string(),
1944 })
1948 Noun::Atom(Atom(3)) => {
1949 break {
1950 if let Noun::Cell(t) = *s.t {
1951 Ok(*t.t)
1952 } else {
1953 Err(Error {
1954 msg: "/[3 a] cannot be evaluated when a is an atom".to_string(),
1955 })
1959 Noun::Atom(Atom(n)) => {
1960 s = Cell {
1961 h: Noun::Atom(Atom(2 + n % 2)).into_box(),
1962 t: Cell {
1963 h: Noun::Atom(Atom(n / 2)).into_box(),
1964 t: s.t,
1966 .fas()?
1967 .into_box(),
1970 Noun::Cell(_) => {
1971 break Err(Error {
1972 msg: "/[a b] cannot be evaluated when a is a cell".to_string(),
1973 })
1980trait Hax {
1981 fn hax(self) -> Result<Noun, Error>;
1984impl Hax for Cell {
1985 fn hax(self) -> Result<Noun, Error> {
1986 let mut s = self;
1987 loop {
1988 if let (Noun::Atom(h), Noun::Cell(t)) = (*s.h, *s.t) {
1989 match h {
1990 Atom(0) => {
1991 break Err(Error {
1992 msg: "#[0 a b] cannot be evaluated".to_string(),
1993 })
1995 Atom(1) => break Ok(*t.h),
1996 Atom(n) if 0 == n % 2 => {
1997 s = Cell {
1998 h: Noun::Atom(Atom(n / 2)).into_box(),
1999 t: Noun::Cell(Cell {
2000 h: Noun::Cell(Cell {
2001 h: t.h,
2002 t: Cell {
2003 h: Noun::Atom(Atom(n + 1)).into_box(),
2004 t: t.t.clone(),
2006 .fas()?
2007 .into_box(),
2008 })
2009 .into_box(),
2010 t: t.t,
2011 })
2012 .into_box(),
2015 Atom(n) => {
2016 s = Cell {
2017 h: Noun::Atom(Atom(n / 2)).into_box(),
2018 t: Noun::Cell(Cell {
2019 h: Noun::Cell(Cell {
2020 h: Cell {
2021 h: Noun::Atom(Atom(n - 1)).into_box(),
2022 t: t.t.clone(),
2024 .fas()?
2025 .into_box(),
2026 t: t.h,
2027 })
2028 .into_box(),
2029 t: t.t,
2030 })
2031 .into_box(),
2035 } else {
2036 break Err(Error {
2037 msg: "#[a b] cannot be evaluated when a is cell and/or b is an atom"
2038 .to_string(),
2039 });
2045trait Tar {
2046 fn tar(self) -> Result<Noun, Error>;
2049impl Tar for Cell {
2050 fn tar(self) -> Result<Noun, Error> {
2051 let mut s = self;
2052 loop {
2053 if let Noun::Cell(t) = *s.t {
2054 match *t.h {
2055 Noun::Atom(Atom(0)) => break Cell { h: t.t, t: s.h }.fas(),
2056 Noun::Atom(Atom(1)) => break Ok(*t.t),
2057 Noun::Atom(Atom(2)) => {
2058 if let Noun::Cell(tt) = *t.t {
2059 s = Cell {
2060 h: Cell {
2061 h: s.h.clone(),
2062 t: tt.h,
2064 .tar()?
2065 .into_box(),
2066 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2068 } else {
2069 break Err(Error {
2070 msg: "*[a 2 b] cannot be evaluated when b is an atom".to_string(),
2071 });
2074 Noun::Atom(Atom(3)) => {
2075 break {
2076 match (Cell { h: s.h, t: t.t }.tar()?) {
2077 Noun::Atom(a) => Ok(Noun::from_loobean(a.wut())),
2078 Noun::Cell(c) => Ok(Noun::from_loobean(c.wut())),
2082 Noun::Atom(Atom(4)) => {
2083 break {
2084 if let Noun::Atom(a) = (Cell { h: s.h, t: t.t }.tar()?) {
2085 Ok(Noun::Atom(a.lus()))
2086 } else {
2087 Err(Error {
2088 msg: "Cannot apply the + operator to a cell".to_string(),
2089 })
2093 Noun::Atom(Atom(5)) => {
2094 break {
2095 if let Noun::Cell(tt) = *t.t {
2096 Ok(Noun::from_loobean(
2097 Cell {
2098 h: Cell {
2099 h: s.h.clone(),
2100 t: tt.h,
2102 .tar()?
2103 .into_box(),
2104 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2106 .tis(),
2107 ))
2108 } else {
2109 Err(Error {
2110 msg: "*[a 5 b] cannot be evaluated when b is an atom"
2111 .to_string(),
2112 })
2116 Noun::Atom(Atom(6)) => {
2117 if let Noun::Cell(tt) = *t.t {
2118 if let Noun::Cell(ttt) = *tt.t {
2119 s = Cell {
2120 h: s.h.clone(),
2121 t: Cell {
2122 h: Noun::Cell(Cell { h: ttt.h, t: ttt.t }).into_box(),
2123 t: Noun::Cell(Cell {
2124 h: Noun::Atom(Atom(0)).into_box(),
2125 t: Cell {
2126 h: Noun::Cell(Cell {
2127 h: Noun::Atom(Atom(2)).into_box(),
2128 t: Noun::Atom(Atom(3)).into_box(),
2129 })
2130 .into_box(),
2131 t: Noun::Cell(Cell {
2132 h: Noun::Atom(Atom(0)).into_box(),
2133 t: Cell {
2134 h: s.h,
2135 t: Noun::Cell(Cell {
2136 h: Noun::Atom(Atom(4)).into_box(),
2137 t: Noun::Cell(Cell {
2138 h: Noun::Atom(Atom(4)).into_box(),
2139 t: tt.h,
2140 })
2141 .into_box(),
2142 })
2143 .into_box(),
2145 .tar()?
2146 .into_box(),
2147 })
2148 .into_box(),
2150 .tar()?
2151 .into_box(),
2152 })
2153 .into_box(),
2155 .tar()?
2156 .into_box(),
2158 } else {
2159 break Err(Error {
2160 msg: "*[a 6 b c] cannot be evaluated when c is an atom"
2161 .to_string(),
2162 });
2164 } else {
2165 break Err(Error {
2166 msg: "*[a 6 b] cannot be evaluated when b is an atom".to_string(),
2167 });
2170 Noun::Atom(Atom(7)) => {
2171 if let Noun::Cell(tt) = *t.t {
2172 s = Cell {
2173 h: Cell { h: s.h, t: tt.h }.tar()?.into_box(),
2174 t: tt.t,
2176 } else {
2177 break Err(Error {
2178 msg: "*[a 7 b] cannot be evaluated when b is an atom".to_string(),
2179 });
2182 Noun::Atom(Atom(8)) => {
2183 if let Noun::Cell(tt) = *t.t {
2184 s = Cell {
2185 h: Noun::Cell(Cell {
2186 h: Cell {
2187 h: s.h.clone(),
2188 t: tt.h,
2190 .tar()?
2191 .into_box(),
2192 t: s.h,
2193 })
2194 .into_box(),
2195 t: tt.t,
2197 } else {
2198 break Err(Error {
2199 msg: "*[a 8 b] cannot be evaluated when b is an atom".to_string(),
2200 });
2203 Noun::Atom(Atom(9)) => {
2204 if let Noun::Cell(tt) = *t.t {
2205 s = Cell {
2206 h: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2207 t: Noun::Cell(Cell {
2208 h: Noun::Atom(Atom(2)).into_box(),
2209 t: Noun::Cell(Cell {
2210 h: Noun::Cell(Cell {
2211 h: Noun::Atom(Atom(0)).into_box(),
2212 t: Noun::Atom(Atom(1)).into_box(),
2213 })
2214 .into_box(),
2215 t: Noun::Cell(Cell {
2216 h: Noun::Atom(Atom(0)).into_box(),
2217 t: tt.h,
2218 })
2219 .into_box(),
2220 })
2221 .into_box(),
2222 })
2223 .into_box(),
2225 } else {
2226 break Err(Error {
2227 msg: "*[a 9 b] cannot be evaluated when b is an atom".to_string(),
2228 });
2231 Noun::Atom(Atom(10)) => {
2232 break if let Noun::Cell(tt) = *t.t {
2233 if let Noun::Cell(tth) = *tt.h {
2234 Cell {
2235 h: tth.h,
2236 t: Noun::Cell(Cell {
2237 h: Cell {
2238 h: s.h.clone(),
2239 t: tth.t,
2241 .tar()?
2242 .into_box(),
2243 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2244 })
2245 .into_box(),
2247 .hax()
2248 } else {
2249 Err(Error {
2250 msg: "*[a 10 b c] cannot be evaluated when b is an atom"
2251 .to_string(),
2252 })
2254 } else {
2255 Err(Error {
2256 msg: "*[a 10 b] cannot be evaluated when b is an atom".to_string(),
2257 })
2260 Noun::Atom(Atom(11)) => {
2261 if let Noun::Cell(tt) = *t.t {
2262 match *tt.h {
2263 Noun::Atom(_) => break Cell { h: s.h, t: tt.t }.tar(),
2264 Noun::Cell(c) => {
2265 s = Cell {
2266 h: Noun::Cell(Cell {
2267 h: Cell {
2268 h: s.h.clone(),
2269 t: c.t,
2271 .tar()?
2272 .into_box(),
2273 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2274 })
2275 .into_box(),
2276 t: Noun::Cell(Cell {
2277 h: Noun::Atom(Atom(0)).into_box(),
2278 t: Noun::Atom(Atom(3)).into_box(),
2279 })
2280 .into_box(),
2284 } else {
2285 break Err(Error {
2286 msg: "*[a 11 b] cannot be evaluated when b is an atom".to_string(),
2287 });
2290 Noun::Atom(Atom(_)) => {
2291 break Err(Error {
2292 msg: "unsupported opcode".to_string(),
2293 })
2295 Noun::Cell(th) => {
2296 break Ok(Noun::Cell(Cell {
2297 h: Cell {
2298 h: s.h.clone(),
2299 t: Noun::Cell(th).into_box(),
2301 .tar()?
2302 .into_box(),
2303 t: Cell { h: s.h, t: t.t }.tar()?.into_box(),
2304 }))
2307 } else {
2308 break Err(Error {
2309 msg: "*[a b] cannot be evaluated when b is an atom".to_string(),
2310 });
2315```
2317## Scala
2319From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
2321```scala
2322package object nnnock {
2324 sealed trait Noun;
2325 case class Atom( value : Int ) extends Noun;
2326 case class Cell( head : Noun, tail : Noun ) extends Noun;
2327 implicit def toAtom( value : Int ) : Atom = Atom( value );
2328 implicit def toInt( atom : Atom ) : Int = atom.value;
2330 def nock( a : Noun ) : Noun = *(a)
2333 object Cell {
2334 private def apply( nl : List[Noun] ) : Cell = {
2335 nl match {
2336 case a :: b :: Nil => Cell(a, b);
2337 case a :: b :: c :: Nil => Cell(a, Cell(b, c));
2338 case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
2341 def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
2344 def ?( noun : Noun ) : Noun = noun match {
2345 case _ : Cell => 0;
2346 case _ : Atom => 1;
2349 @tailrec def plus( noun : Noun ) : Noun = noun match {
2350 case a : Atom => 1 + a;
2351 case c : Cell => plus( c ); //intentional endless spin
2354 def heq( noun : Noun ) : Atom = noun match {
2355 case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
2356 case Cell( a : Cell, b : Atom ) => 1;
2357 case Cell( a : Atom, b : Cell ) => 1;
2358 case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
2359 case a : Atom => heq( a ); //intentional endless spin
2362 def /( noun : Noun ) : Noun = noun match {
2363 case Cell(Atom(1), a) => a;
2364 case Cell(Atom(2), Cell(a, b)) => a;
2365 case Cell(Atom(3), Cell(a, b)) => b;
2366 case Cell(Atom(value), b ) => {
2367 val a = value / 2;
2368 val num = if ( value % a == 0 ) 2 else 3;
2369 /(Cell(num, /(Cell(a, b))));
2371 case a => /( a ); //intentional endless spin
2375 def *( noun : Noun ) : Noun = noun match {
2376 case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
2377 case Cell( a, Cell(Atom(value), tail) ) => {
2378 (value, tail) match {
2379 case (0, b) => /( Cell(b, a) );
2380 case (1, b) => b;
2381 case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
2382 case (3, b) => ?( *( Cell(a,b) ) );
2383 case (4, b) => plus( *( Cell(a,b) ) );
2384 case (5, b) => heq( *( Cell(a,b) ) );
2385 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?
2386 case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
2387 case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
2388 case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
2389 case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
2390 case (10, Cell(b, c)) => *( Cell(a,c) );
2391 case _ => *( noun ); //intentional endless spin
2394 case a => *( a ); //intentional endless spin
2397```
2399## Scheme
2401From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
2403```scheme
2404(import (rnrs (6)))
2406(define (i a) a)
2408(define (n a r)
2409 (cond
2410 ((list? a)
2411 (let ((l (length a)))
2412 (cond
2413 ((equal? l 0) (raise 1))
2414 ((equal? l 1) (r (car a)))
2415 (else
2416 (let ((t (cond
2417 ((equal? l 2) (cadr a))
2418 (else (cdr a)))))
2419 (n (car a)
2420 (lambda (p) (n t
2421 (lambda (q) (r (cons p q)))))))))))
2422 ((fixnum? a) (r a))
2423 (else (raise 2))))
2425(define (wut a)
2426 (cond
2427 ((fixnum? a) 1)
2428 (else 0)))
2430(define (lus a)
2431 (cond
2432 ((equal? (wut a) 0) (raise 3))
2433 (else (+ 1 a))))
2435(define (tis a)
2436 (cond
2437 ((equal? (wut a) 1) (raise 4))
2438 ((equal? (car a) (cdr a)) 0)
2439 (else 1)))
2441(define (fas a r)
2442 (cond
2443 ((equal? (wut a) 1) (raise 5))
2444 (else
2445 (let ((h (car a))
2446 (t (cdr a)))
2447 (cond
2448 ((not (fixnum? h)) (raise 6))
2449 ((equal? h 0) (raise 7))
2450 ((equal? h 1) (r t))
2451 ((fixnum? t) (raise 8))
2452 ((equal? h 2) (r (car t)))
2453 ((equal? h 3) (r (cdr t)))
2454 (else
2455 (fas (cons (div h 2) t)
2456 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
2457 (lambda (q) (r q)))))))))))
2459(define (tar a r)
2460 (cond
2461 ((equal? (wut a) 1) (raise 9))
2462 (else
2463 (let ((s (car a))
2464 (f (cdr a)))
2465 (cond
2466 ((equal? (wut f) 1) (raise 10))
2467 (else
2468 (let ((o (car f))
2469 (v (cdr f)))
2470 (cond
2471 ((equal? (wut o) 0) (tar (cons s o)
2472 (lambda (p) (tar (cons s v)
2473 (lambda (q) (r (cons p q)))))))
2474 ((equal? o 0) (r (fas (cons v s) i)))
2475 ((equal? o 1) (r v))
2476 ((equal? o 3) (tar (cons s v)
2477 (lambda (p) (r (wut p)))))
2478 ((equal? o 4) (tar (cons s v)
2479 (lambda (p) (r (lus p)))))
2480 ((equal? o 5) (tar (cons s v)
2481 (lambda (p) (r (tis p)))))
2482 ((equal? (wut v) 1) (raise 11))
2483 (else
2484 (let ((x (car v))
2485 (y (cdr v)))
2486 (cond
2487 ((equal? o 2) (tar (cons s x)
2488 (lambda (p) (tar (cons s y)
2489 (lambda (q) (tar (cons p q)
2490 (lambda (u) (r u))))))))
2491 ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
2492 (lambda (p) (r p))))
2493 ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
2494 (lambda (p) (r p))))
2495 ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
2496 (lambda (p) (r p))))
2497 ((equal? o 10) (cond
2498 ((equal? (wut x) 1) (tar (cons s y)
2499 (lambda (p) (r p))))
2500 (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
2501 (lambda (p) (r p))))))
2502 ((equal? (wut y) 1) (raise 12))
2503 ((equal? o 6) (tar (n (list
2504 (list s)
2506 (list 0 1)
2508 (list 1 (list (car y)) (list (cdr y)))
2509 (list 1 0)
2511 (list 1 2 3)
2512 (list 1 0)
2515 (list x))
2516 i)
2517 (lambda (p) (r p))))
2518 (else (raise 13)))))))))))))
2519```
2521## Swift
2523```swift
2524import Foundation
2525// 1 :: A noun is an atom or a cell.
2526// 2 :: An atom is a natural number.
2527// 3 :: A cell is an ordered pair of nouns.
2528// 4
2529// 5 :: nock(a) *a
2530// 6 :: [a b c] [a [b c]]
2531// 7
2532// 8 :: ?[a b] 0
2533// 9 :: ?a 1
2534// 10 :: +[a b] +[a b]
2535// 11 :: +a 1 + a
2536// 12 :: =[a a] 0
2537// 13 :: =[a b] 1
2538// 14 :: =a =a
2539// 15
2540// 16 :: /[1 a] a
2541// 17 :: /[2 a b] a
2542// 18 :: /[3 a b] b
2543// 19 :: /[(a + a) b] /[2 /[a b]]
2544// 20 :: /[(a + a + 1) b] /[3 /[a b]]
2545// 21 :: /a /a
2546// 22
2547// 23 :: *[a [b c] d] [*[a b c] *[a d]]
2548// 24
2549// 25 :: *[a 0 b] /[b a]
2550// 26 :: *[a 1 b] b
2551// 27 :: *[a 2 b c] *[*[a b] *[a c]]
2552// 28 :: *[a 3 b] ?*[a b]
2553// 29 :: *[a 4 b] +*[a b]
2554// 30 :: *[a 5 b] =*[a b]
2555// 31
2556// 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]
2557// 33 :: *[a 7 b c] *[a 2 b 1 c]
2558// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2559// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2560// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2561// 37 :: *[a 10 b c] *[a c]
2562// 38
2563// 39 :: *a *a
2565// 1 :: A noun is an atom or a cell.
2566public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
2568 // 2 :: An atom is a natural number.
2569 public typealias ATOM = UIntMax
2571 case Atom(ATOM)
2572 // 3 :: A cell is an ordered pair of nouns.
2573 case Cell(Noun, Noun)
2574 case Invalid
2576 public static var YES: Noun { return .Atom(0) }
2577 public static var NO: Noun { return .Atom(1) }
2579 public init(_ noun: Noun) { self = noun }
2581 // 6 :: [a b c] [a [b c]]
2582 public init(_ nouns: [Noun]) {
2583 self = .Invalid
2584 if nouns.count > 0 {
2585 var reverse = nouns.reverse().generate()
2586 self = reverse.next()!
2587 while let n = reverse.next() {
2588 self = .Cell(n, self)
2593 // protocol IntegerLiteralConvertible
2594 public typealias IntegerLiteralType = ATOM
2595 public init(integerLiteral value: IntegerLiteralType) {
2596 self = .Atom(value)
2599 // protocol ArrayLiteralConvertible
2600 public typealias Element = Noun
2601 public init(arrayLiteral elements: Element...) {
2602 self = Noun(elements)
2605 // Array subscript
2606 public subscript(axis: ATOM) -> Noun {
2607 return fas(.Cell(.Atom(axis), self))
2610 // protocol Hashable
2611 public var hashValue: Int {
2612 //return self.description.hashValue
2613 switch self {
2614 case let .Atom(a):
2615 return a.hashValue
2616 case let .Cell(a, b):
2617 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2618 default:
2619 abort()
2623 // protocol CustomStringConvertible
2624 public var description: String {
2625 return describe()
2628 private func describe(depth: Int = 0) -> String {
2629 var sub = ""
2630 let next = depth+1
2631 switch self {
2632 case .Invalid:
2633 return "[%INVALID%]"
2634 case let .Atom(atom):
2635 return "\(atom)"
2636 case let .Cell(.Cell(a, b), c):
2637 sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
2638 case let .Cell(a, b):
2639 sub = "\(a.describe(next)) \(b.describe(next))"
2641 return depth == 0 ? "[\(sub)]" : sub
2645// protocol Equatable
2646public func == (left: Noun, right: Noun) -> Bool
2648 switch (left, right) {
2649 case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
2650 case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
2651 case (.Invalid, .Invalid): return true
2652 default: return false
2656public func wut(noun: Noun) -> Noun
2658 switch noun {
2659 // 8 :: ?[a b] 0
2660 case .Cell:
2661 return Noun.YES
2662 case .Atom:
2663 // 9 :: ?a 1
2664 return Noun.NO
2665 default:
2666 //return wut(noun)
2667 abort()
2671public func lus(noun: Noun) -> Noun
2673 if case let .Atom(a) = noun {
2674 // 11 :: +a 1 + a
2675 return .Atom(1+a)
2677 // 10 :: +[a b] +[a b]
2678 //return lus(noun)
2679 abort()
2682public func tis(noun: Noun) -> Noun
2684 if case let .Cell(a, b) = noun {
2685 // 12 :: =[a a] 0
2686 // 13 :: =[a b] 1
2687 return (a == b) ? Noun.YES : Noun.NO
2689 // 14 :: =a =a
2690 //return tis(noun)
2691 abort()
2694public func fas(noun: Noun) -> Noun
2696 switch noun {
2697 // 16 :: /[1 a] a
2698 case let .Cell(1, a):
2699 return a
2700 // 17 :: /[2 a b] a
2701 case let .Cell(2, .Cell(a, _)):
2702 return a
2703 // 18 :: /[3 a b] b
2704 case let .Cell(3, .Cell(_, b)):
2705 return b
2706 // 19 :: /[(a + a) b] /[2 /[a b]]
2707 // 20 :: /[(a + a + 1) b] /[3 /[a b]]
2708 case let .Cell(.Atom(axis), tree):
2709 let inner = Noun.Atom(axis / 2)
2710 let outer = Noun.Atom(2 + (axis % 2))
2711 return fas(.Cell(outer, fas(.Cell(inner, tree))))
2712 default:
2713 // 21 :: /a /a
2714 //return fas(noun)
2715 abort()
2719public func tar(noun: Noun) -> Noun
2721 switch noun {
2722 case let .Cell(a, formula):
2723 switch formula {
2724 // 23 :: *[a [b c] d] [*[a b c] *[a d]]
2725 case let .Cell(.Cell(b, c), d):
2726 return .Cell(tar([a, b, c]), tar([a, d]))
2728 // 25 :: *[a 0 b] /[b a]
2729 case let .Cell(0, b):
2730 return fas([b, a])
2732 // 26 :: *[a 1 b] b
2733 case let .Cell(1, b):
2734 return b
2736 // 27 :: *[a 2 b c] *[*[a b] *[a c]]
2737 case let .Cell(2, .Cell(b, c)):
2738 return tar([tar([a, b]), tar([a, c])])
2740 // 28 :: *[a 3 b] ?*[a b]
2741 case let .Cell(3, b):
2742 return wut(tar([a, b]))
2744 // 29 :: *[a 4 b] +*[a b]
2745 case let .Cell(4, b):
2746 return lus(tar([a, b]))
2748 // 30 :: *[a 5 b] =*[a b]
2749 case let .Cell(5, b):
2750 return tis(tar([a, b]))
2752 // 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]
2753 case let .Cell(6, .Cell(b, .Cell(c, d))):
2754 return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
2756 // 33 :: *[a 7 b c] *[a 2 b 1 c]
2757 case let .Cell(7, .Cell(b, c)):
2758 return tar([a, 2, b, 1, c])
2760 // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2761 case let .Cell(8, .Cell(b, c)):
2762 return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
2764 // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2765 case let .Cell(9, .Cell(b, c)):
2766 return tar([a, 7, c, 2, [0, 1], 0, b])
2768 // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2769 case let .Cell(10, .Cell(.Cell(_, c), d)):
2770 return tar([a, 8, c, 7, [0, 3], d])
2772 // 37 :: *[a 10 b c] *[a c]
2773 case let .Cell(10, .Cell(_, c)):
2774 return tar([a, c]);
2776 default:
2777 //return tar(noun)
2778 abort()
2780 default:
2781 //return tar(noun)
2782 abort()
2787public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2789public func dao(formula: Noun) -> Noun->Noun
2791 if let cached = nock_functions[formula] {
2792 return cached
2795 let compiler = { () -> Noun -> Noun in
2796 switch formula {
2797 case let .Cell(.Cell(b, c), d): // Distribution
2798 let (p, q) = (dao(.Cell(b, c)), dao(d))
2799 return { a in .Cell(p(a), q(a)) }
2801 case let .Cell(0, b): // Axis
2802 return { a in fas(.Cell(b, a)) }
2804 case let .Cell(1, b): // Just
2805 return { _ in b }
2807 case let .Cell(2, .Cell(b, c)): // Fire
2808 let (f, g) = (dao(b), dao(c))
2809 return { a in dao(g(a))(f(a)) }
2811 case let .Cell(3, b): // Depth
2812 let f = dao(b)
2813 return { a in wut(f(a)) }
2815 case let .Cell(4, b): // Bump
2816 let f = dao(b)
2817 return { a in lus(f(a)) }
2819 case let .Cell(5, b): // Same
2820 let f = dao(b)
2821 return { a in tis(f(a)) }
2823 case let .Cell(6, .Cell(b, .Cell(c, d))): // If
2824 let (p, q, r) = (dao(b), dao(c), dao(d))
2825 return { a in
2826 switch p(a) {
2827 case Noun.self.YES:
2828 return q(a)
2829 case Noun.self.NO:
2830 return r(a)
2831 default:
2832 return tar(.Cell(a, formula))
2836 case let .Cell(7, .Cell(b, c)): // Compose
2837 let (f, g) = (dao(b), dao(c))
2838 return { a in g(f(a)) }
2840 case let .Cell(8, .Cell(b, c)): // Push
2841 let (f, g) = (dao(b), dao(c))
2842 return { a in g(.Cell(f(a), a)) }
2844 case let .Cell(9, .Cell(b, c)): // Call
2845 let f = dao(c)
2846 return { a in
2847 let core = f(a)
2848 let arm = dao(fas(.Cell(b, core)))
2849 return arm(core)
2852 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2853 let ignore = dao(c)
2854 let f = dao(d)
2855 return { a in ignore(a); return f(a) }
2857 case let .Cell(10, .Cell(_, c)): // Hint
2858 let f = dao(c)
2859 return { a in f(a) }
2861 default:
2862 return { a in tar(.Cell(a, formula)) }
2866 let r = compiler()
2867 nock_functions[formula] = r
2868 return r
2871public func nock(n: Noun) -> Noun
2873 if case let .Cell(a, b) = n {
2874 let f = dao(b)
2875 return f(a)
2877 return nock(n)
2879```