2title = "Implementations"
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.):
21- [JavaScript](#javascript)
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).
41/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
44_n_nock_on(u3_noun bus, u3_noun fol)
56 if ( c3y == u3r_du(hib) ) {
59 poz = _n_nock_on(u3k(bus), u3k(hib));
60 riv = _n_nock_on(bus, u3k(gal));
63 return u3i_cell(poz, riv);
66 default: return u3m_bail(c3__exit);
69 if ( c3n == u3r_ud(gal) ) {
70 return u3m_bail(c3__exit);
73 u3_noun pro = u3k(u3at(gal, bus));
75 u3a_lose(bus); u3a_lose(fol);
79 c3_assert(!"not reached");
82 u3_noun pro = u3k(gal);
84 u3a_lose(bus); u3a_lose(fol);
87 c3_assert(!"not reached");
90 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
91 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
98 c3_assert(!"not reached");
103 gof = _n_nock_on(bus, u3k(gal));
106 u3a_lose(gof); u3a_lose(fol);
109 c3_assert(!"not reached");
114 gof = _n_nock_on(bus, u3k(gal));
120 c3_assert(!"not reached");
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);
129 c3_assert(!"not reached");
132 u3_noun b_gal, c_gal, d_gal;
134 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
136 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
141 } else if ( 1 == tys ) {
143 } else return u3m_bail(c3__exit);
150 c3_assert(!"not reached");
153 u3_noun b_gal, c_gal;
155 u3x_cell(gal, &b_gal, &c_gal);
157 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
158 u3_noun nex = u3k(c_gal);
166 c3_assert(!"not reached");
169 u3_noun b_gal, c_gal;
171 u3x_cell(gal, &b_gal, &c_gal);
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);
183 c3_assert(!"not reached");
186 u3_noun b_gal, c_gal;
188 u3x_cell(gal, &b_gal, &c_gal);
190 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
194 pro = u3j_kick(seb, b_gal);
197 if ( u3_none != pro ) {
202 if ( c3n == u3r_ud(b_gal) ) {
203 return u3m_bail(c3__exit);
206 u3_noun nex = u3k(u3at(b_gal, seb));
216 c3_assert(!"not reached");
219 u3_noun p_gal, q_gal;
221 u3x_cell(gal, &p_gal, &q_gal);
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;
231 hod = _n_nock_on(u3k(bus), u3k(c_gal));
235 u3_noun b_gal = p_gal;
236 u3_noun c_gal = q_gal;
244 return _n_hint(zep, hod, bus, nex);
249 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
250 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
254 val = u3m_soft_esc(ref, u3k(gof));
257 if ( !_(u3du(val)) ) {
258 u3m_bail(u3nt(1, gof, 0));
260 if ( !_(u3du(u3t(val))) ) {
262 // replace with proper error stack push
264 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
265 return u3m_bail(c3__exit);
272 pro = u3k(u3t(u3t(val)));
278 c3_assert(!"not reached");
286From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
290 (:import anock.NockException))
292(declare atom? cell? cell)
295 "A noun is an atom or a cell."
298 (or (atom? noun) (cell? noun))))
301 "An atom is a natural number."
304 (and (integer? noun) (>= noun 0))))
307 "A cell is an ordered pair of nouns."
312 (not= 2 (count noun)) false
313 :else (and (noun? (first noun))
314 (noun? (second noun)))))
317 "= (pronounced 'tis') tests a cell for equality."
319 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
324 "? (pronounced 'wut') tests whether a noun is a cell."
329 :else (throw (anock.NockException. "Invalid noun."))))
332 "+ (pronounced 'lus') adds 1 to an atom."
334 (if (atom? noun) (inc noun)
335 (throw (anock.NockException. "Can only lus atoms."))))
338 "/ (pronounced 'fas') is a tree address function."
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))))
349 (even? a) (fas [2 (fas [(/ a 2) b])])
350 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
353 "* (pronounced 'tar') means Nock"
355 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
357 (let [noun (cell noun) [x [y z]] noun]
359 (cell? y) (cell (tar [x y]) (tar [x z]))
360 (zero? y) (fas [z x])
362 (= 3 y) (wut (tar [x z]))
363 (= 4 y) (lus (tar [x z]))
364 (= 5 y) (tis (tar [x z]))
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])
376 (catch RuntimeException e
377 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
381; Some convenience functions
383 (if (and (= 1 (count x)) (coll? (first x)))
388 "[a b c] -> [a [b c]]"
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)])))
398 (if (apply atom? nouns)
399 (throw (anock.NockException. "Cannot convert atom to cell."))
400 (apply* bracket nouns)))
405From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
409using System.Collections.Generic;
412using System.Text.RegularExpressions;
414namespace NockInterpreter
418 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
420 public static Noun Nock(Noun noun)
424 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
429 if (Atom.IsAtom(noun))
430 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
433 Noun subject = noun.n1;
434 if (Noun.IsCell(noun.n2))
436 Cell formula = (Cell)noun.n2;
437 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
439 Atom op = (Atom)formula.n1;
440 Noun operands = formula.n2;
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))
453 Noun a = Nock(subject, operands.n1);
454 Noun b = Nock(subject, operands.n2);
455 noun = Noun.CreateNoun(a, b);
457 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
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))
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 + "]");
477 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
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))
483 Noun b = operands.n1;
484 Noun c = operands.n2;
485 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
487 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
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))
493 Noun b = operands.n1;
494 Noun c = operands.n2;
495 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
497 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
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))
503 Noun b = operands.n1;
504 Noun c = operands.n2;
505 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
507 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
509 throw new Exception("Atom after operand 9: " + operands.ToString());
511 if (Noun.IsCell(operands))
513 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
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 + "]");
520 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
522 else // 37 :: *[a 10 b c] *[a c]
524 Noun c = operands.n2;
525 noun = Noun.CreateNoun(subject, c);
527 // return Nock(subject, c);
530 throw new Exception("Atom after operand 10: " + operands.ToString());
532 throw new Exception("Unknown operand: " + op.value);
535 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
537 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
538 return memocache[noun.ToString()];
542 throw new Exception("Unhandled pattern");
545 public static Noun Nock(string program)
547 Noun noun = Noun.CreateNoun(program);
551 public static Noun Nock(Noun n1, Noun n2)
553 Noun noun = Noun.CreateNoun(n1, n2);
557 private static Noun tis(Noun noun)
559 if (Noun.IsAtom(noun.ToString()))
560 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
563 Cell cell = (Cell)noun;
565 if (cell.n1.ToString() == cell.n2.ToString())
566 return Noun.CreateNoun("0");
568 return Noun.CreateNoun("1");
572 private static Noun lus(Noun noun)
574 if (Noun.IsAtom(noun.ToString()))
578 return Noun.CreateNoun(v.ToString());
581 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
584 private static Noun wut(Noun noun)
586 if (Noun.IsAtom(noun.ToString()))
587 return Noun.CreateNoun("1");
589 return Noun.CreateNoun("0");
592 private static Noun fas(Noun n1, Noun n2)
594 Noun noun = Noun.CreateNoun(n1, n2);
598 private static Noun fas(Noun noun)
600 if (Noun.IsAtom(noun.ToString()))
601 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
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());
613 else if (a.value >= 2)
615 if (!Noun.IsCell(c.n2.ToString()))
617 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
621 Cell c2 = (Cell)c.n2;
624 else if (a.value == 3)
626 else if (a.value % 2 == 0)
628 int half = a.value / 2;
629 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
631 else if (a.value % 2 == 1)
633 int half = a.value / 2;
634 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
638 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
643 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
653 // takes a program, returns a pair of nouns, stringified.
654 public static Tuple<string, string> SplitCell(string program)
659 // split the string right after the first space
660 foreach (char c in program)
670 // if we see a space, and our stack count is at 1, then we've found our split point
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))
679 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
685 throw new Exception("Invalid char in cell: " + c);
688 throw new Exception("Invalid cell: " + program);
691 public static bool IsCell(string program)
693 // check if cell is valid, as above but make sure no space after bracket
694 // valid tokens are: space, 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.
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)
716 if (!(c == '[' || IsInt(c)))
721 if (!(IsInt(c) || c == ' ' || c == ']'))
726 if (!(c == ']' || c == ' '))
731 if (!(c == '[' || IsInt(c)))
740 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
744 // We should end with stack count of zero
751 public static bool IsInt(char c)
768 public static bool IsValidChar(char c)
779 public static bool IsAtom(string program)
782 if (int.TryParse(program, out i))
790 public static bool IsAtom(Noun noun)
792 return IsAtom(noun.ToString());
795 public static bool IsCell(Noun noun)
797 return IsCell(noun.ToString());
800 public static Noun CreateNoun(string program)
803 return new Atom(program);
805 return new Cell(program);
808 public static Noun CreateNoun(Noun n1, Noun n2)
810 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
813 public static Noun CreateNoun(string p1, Noun n2)
815 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
818 public static Noun CreateNoun(Noun n1, string p2)
820 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
823 public static Noun CreateNoun(string p1, string p2)
825 return CreateNoun("[" + p1 + " " + p2 + "]");
833 public override string ToString()
835 return value.ToString();
838 public Atom(string program)
843 bool result = int.TryParse(program, out i);
847 throw new ArgumentException("Invalid Atom: " + program);
855 public override string ToString()
857 return "[" + n1.ToString() + " " + n2.ToString() + "]";
860 public Cell(string program)
864 Tuple<string, string> split = SplitCell(program);
865 n1 = CreateNoun(split.Item1);
866 n2 = CreateNoun(split.Item2);
869 throw new ArgumentException("Invalid Cell: " + program);
877From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
904 } else if (a.size() >= 2) {
906 n(a.size() == 2 ? a[1] : a.tail(), { h ->
911 throw new IllegalStateException()
916 throw new IllegalStateException()
928 throw new IllegalStateException()
936 throw new IllegalStateException()
949def fas(def a, def r) {
951 throw new IllegalStateException()
955 throw new IllegalStateException()
959 throw new IllegalStateException()
964 throw new IllegalStateException()
971 fas([h.intdiv(2), t], { p ->
972 fas([2 + h.mod(2), p], { q ->
988def tar(def a, def r) {
990 throw new IllegalStateException()
995 throw new IllegalStateException()
1008 } else if (o == 1) {
1010 } else if (o == 3) {
1014 } else if (o == 4) {
1018 } else if (o == 5) {
1024 throw new IllegalStateException()
1036 } else if (o == 7) {
1037 tar(n([s, 2, x, 1, y]), {
1040 } else if (o == 8) {
1041 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1044 } else if (o == 9) {
1045 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1048 } else if (o == 10) {
1054 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1060 throw new IllegalStateException()
1063 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1067 throw new IllegalStateException()
1077From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
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
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
1100tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
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)
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 :-
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)
1139 [$(fol -.fol) $(fol +.fol)]
1146 =+ [now=(cap b.fol) lat=(mas b.fol)]
1147 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1154 $(sub -.ben, fol +.ben)
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))
1183From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1186(function (self, factory) {
1189 if (typeof define === 'function' && define.amd) {
1191 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1192 module.exports = factory()
1194 self.nock = factory()
1196}(this, function () {
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
1207 var useMacros = false
1213 * `s` is a subject noun,
1214 * `f` is a formula (or cell of formulas)
1220 * wut (?): test for atom (1) or cell (0)
1226 return typeof n === 'number' ? 1 : 0
1230 * lus (+): increment an atom
1236 if (wut(n) === 0) throw new Error('lus cell')
1241 * tis (=): test equality
1248 if (wut(n) === 1) throw new Error('tis atom')
1249 return deepEqual(n[0], n[1]) ? 0 : 1
1253 * fas (/): resolve a tree address
1258 * /[(a + a) b] /[2 /[a b]]
1259 * /[(a + a + 1) b] /[3 /[a b]]
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))
1276 * slot (0): resolve a tree address
1280 function slot (s, f) {
1283 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1289 * constant (1): return the formula regardless of subject
1293 function constant (s, f) {
1298 * evaluate (2): evaluate the product of second formula against the product of the first
1300 * *[a 2 b c] *[*[a b] *[a c]]
1302 function evaluate (s, f) {
1303 return nock(nock(s, f[0]), nock(s, f[1]))
1307 * cell (3): test if the product is a cell
1311 function cell (s, f) {
1312 return wut(nock(s, f))
1316 * incr (4): increment the product
1320 function incr (s, f) {
1321 return lus(nock(s, f))
1325 * eq (5): test for equality between nouns in the product
1329 function eq (s, f) {
1330 return tis(nock(s, f))
1333 /* macro-formulas */
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]
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')
1354 * compose (7): evaluate formulas composed left-to-right
1356 * *[a 7 b c] *[a 2 b 1 c]
1358 function macroCompose (s, f) {
1359 return nock(s, [2, [f[0], [1, f[1]]]])
1362 function compose (s, f) {
1364 // return nock(nock(s, f[0]), constant(s, f[1]))
1365 return nock(nock(s, f[0]), f[1])
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]
1373 function macroExtend (s, f) {
1374 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1377 function extend (s, f) {
1379 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1380 return nock([nock(s, f[0]), s], f[1])
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]
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]))
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]
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')
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]
1425 * *[a [b c] d] [*[a b c] *[a d]]
1428 function nock (s, f) {
1429 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
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
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))
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])
1490 if (!formula) throw new Error('formula required')
1497 return nock(subject, formula)
1501 nock: nockInterface,
1503 useMacros: function (arg) {
1504 useMacros = arg === undefined || arg
1509 parseNoun: parseNoun,
1510 deepEqual: deepEqual
1527 macroCompose: macroCompose,
1529 macroExtend: macroExtend,
1531 macroInvoke: macroInvoke,
1533 macroHint: macroHint,
1542From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1545#!/usr/bin/env python3
1554 return (lst[0], l(*lst[1:]))
1562 if isinstance(noun, int):
1570 if isinstance(noun, int):
1578 if noun[0] == noun[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]))))
1599 if isinstance(noun[1][0], int):
1601 return slot((noun[1][1], noun[0]))
1602 elif noun[1][0] == 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]))
1624 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1626 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1631From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1636 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1641 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1646 depth = max_depth(arr)
1648 1.up_to(8) do |depth|
1650 min = 2 ** (depth - 1)
1651 max = (2 ** depth) - 1
1652 min.upto(max) { |axis|
1658 return arr unless arr.is_a?(Array)
1661 arr[size - 2] = [ arr[size - 2], arr.pop ]
1663 arr = arr.map { |x| norm(x) }
1667 arr.is_a?(Array) ? YES : NO
1671 raise "not an atom" unless atom.is_a?(Fixnum)
1676 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1677 ( arr[0] == arr[1] ) ? YES : NO
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))
1691 raise "error: nocking an atom" unless arr.is_a?(Array)
1697 if oper.is_a?(Array)
1698 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1710 b_prime = slot(2, b)
1712 nock( [ nock([a, b_primce]), nock([a, c]) ])
1724 b_prime = slot(2, b)
1727 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1730 b_prime = slot(2, b)
1732 nock( norm ([a, 2, b_prime, 1, c]))
1735 b_prime = slot(2, b)
1737 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1740 b_prime = slot(2, b)
1742 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1745 if wut(slot(2,b)) == TRUE
1746 b_prime = slot(4, b)
1750 nock( norm ([a, 8, c, 7, [0, 3], d]))
1752 b_prime = slot(2, b)
1754 nock( norm ([a, 10, [b, c]]))
1757 raise "error: unknown opcode #{oper.inspect}"
1764From [Peter McEvoy](https://github.com/mcevoypeter/nock/tree/main/src):
1767#![allow(unused_parens)]
1769use std::{error, fmt};
1777impl Clone for Noun {
1778 fn clone(&self) -> Self {
1780 Noun::Atom(a) => Noun::Atom(Atom(a.0)),
1781 Noun::Cell(c) => Noun::Cell(Cell {
1789impl PartialEq for Noun {
1790 fn eq(&self, other: &Self) -> bool {
1791 if let (Noun::Atom(lh), Noun::Atom(rh)) = (&*self, &*other) {
1793 } else if let (Noun::Cell(lh), Noun::Cell(rh)) = (&*self, &*other) {
1801impl fmt::Display for Noun {
1802 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1805 write!(f, "{}", a.0)
1807 Noun::Cell(ref c) => {
1808 write!(f, "[{} {}]", c.h, c.t)
1815 fn from_loobean(loob: Loobean) -> Self {
1817 Loobean::Yes => Noun::Atom(Atom(0)),
1818 Loobean::No => Noun::Atom(Atom(1)),
1822 fn into_box(self) -> Box<Self> {
1827#[derive(Clone, Debug, PartialEq)]
1836impl Clone for Cell {
1837 fn clone(&self) -> Self {
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
1857#[derive(Debug, PartialEq)]
1864 fn from_boolean(b: bool) -> Self {
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 {}
1887 fn wut(&self) -> Loobean;
1891 fn wut(&self) -> Loobean {
1897 fn wut(&self) -> Loobean {
1903 fn lus(self) -> Atom;
1907 fn lus(self) -> Atom {
1913 fn tis(&self) -> Loobean;
1917 fn tis(&self) -> Loobean {
1918 Loobean::from_boolean(self.h == self.t)
1923 fn fas(self) -> Result<Noun, Error>;
1927 fn fas(self) -> Result<Noun, Error> {
1931 Noun::Atom(Atom(0)) => {
1933 msg: "/[0 a] cannot be evaluated".to_string(),
1936 Noun::Atom(Atom(1)) => break Ok(*s.t),
1937 Noun::Atom(Atom(2)) => {
1939 if let Noun::Cell(t) = *s.t {
1943 msg: "/[2 a] cannot be evaluated when a is an atom".to_string(),
1948 Noun::Atom(Atom(3)) => {
1950 if let Noun::Cell(t) = *s.t {
1954 msg: "/[3 a] cannot be evaluated when a is an atom".to_string(),
1959 Noun::Atom(Atom(n)) => {
1961 h: Noun::Atom(Atom(2 + n % 2)).into_box(),
1963 h: Noun::Atom(Atom(n / 2)).into_box(),
1972 msg: "/[a b] cannot be evaluated when a is a cell".to_string(),
1981 fn hax(self) -> Result<Noun, Error>;
1985 fn hax(self) -> Result<Noun, Error> {
1988 if let (Noun::Atom(h), Noun::Cell(t)) = (*s.h, *s.t) {
1992 msg: "#[0 a b] cannot be evaluated".to_string(),
1995 Atom(1) => break Ok(*t.h),
1996 Atom(n) if 0 == n % 2 => {
1998 h: Noun::Atom(Atom(n / 2)).into_box(),
1999 t: Noun::Cell(Cell {
2000 h: Noun::Cell(Cell {
2003 h: Noun::Atom(Atom(n + 1)).into_box(),
2017 h: Noun::Atom(Atom(n / 2)).into_box(),
2018 t: Noun::Cell(Cell {
2019 h: Noun::Cell(Cell {
2021 h: Noun::Atom(Atom(n - 1)).into_box(),
2037 msg: "#[a b] cannot be evaluated when a is cell and/or b is an atom"
2046 fn tar(self) -> Result<Noun, Error>;
2050 fn tar(self) -> Result<Noun, Error> {
2053 if let Noun::Cell(t) = *s.t {
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 {
2066 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2070 msg: "*[a 2 b] cannot be evaluated when b is an atom".to_string(),
2074 Noun::Atom(Atom(3)) => {
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)) => {
2084 if let Noun::Atom(a) = (Cell { h: s.h, t: t.t }.tar()?) {
2085 Ok(Noun::Atom(a.lus()))
2088 msg: "Cannot apply the + operator to a cell".to_string(),
2093 Noun::Atom(Atom(5)) => {
2095 if let Noun::Cell(tt) = *t.t {
2096 Ok(Noun::from_loobean(
2104 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2110 msg: "*[a 5 b] cannot be evaluated when b is an atom"
2116 Noun::Atom(Atom(6)) => {
2117 if let Noun::Cell(tt) = *t.t {
2118 if let Noun::Cell(ttt) = *tt.t {
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(),
2126 h: Noun::Cell(Cell {
2127 h: Noun::Atom(Atom(2)).into_box(),
2128 t: Noun::Atom(Atom(3)).into_box(),
2131 t: Noun::Cell(Cell {
2132 h: Noun::Atom(Atom(0)).into_box(),
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(),
2160 msg: "*[a 6 b c] cannot be evaluated when c is an atom"
2166 msg: "*[a 6 b] cannot be evaluated when b is an atom".to_string(),
2170 Noun::Atom(Atom(7)) => {
2171 if let Noun::Cell(tt) = *t.t {
2173 h: Cell { h: s.h, t: tt.h }.tar()?.into_box(),
2178 msg: "*[a 7 b] cannot be evaluated when b is an atom".to_string(),
2182 Noun::Atom(Atom(8)) => {
2183 if let Noun::Cell(tt) = *t.t {
2185 h: Noun::Cell(Cell {
2199 msg: "*[a 8 b] cannot be evaluated when b is an atom".to_string(),
2203 Noun::Atom(Atom(9)) => {
2204 if let Noun::Cell(tt) = *t.t {
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(),
2215 t: Noun::Cell(Cell {
2216 h: Noun::Atom(Atom(0)).into_box(),
2227 msg: "*[a 9 b] cannot be evaluated when b is an atom".to_string(),
2231 Noun::Atom(Atom(10)) => {
2232 break if let Noun::Cell(tt) = *t.t {
2233 if let Noun::Cell(tth) = *tt.h {
2236 t: Noun::Cell(Cell {
2243 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2250 msg: "*[a 10 b c] cannot be evaluated when b is an atom"
2256 msg: "*[a 10 b] cannot be evaluated when b is an atom".to_string(),
2260 Noun::Atom(Atom(11)) => {
2261 if let Noun::Cell(tt) = *t.t {
2263 Noun::Atom(_) => break Cell { h: s.h, t: tt.t }.tar(),
2266 h: Noun::Cell(Cell {
2273 t: Cell { h: s.h, t: tt.t }.tar()?.into_box(),
2276 t: Noun::Cell(Cell {
2277 h: Noun::Atom(Atom(0)).into_box(),
2278 t: Noun::Atom(Atom(3)).into_box(),
2286 msg: "*[a 11 b] cannot be evaluated when b is an atom".to_string(),
2290 Noun::Atom(Atom(_)) => {
2292 msg: "unsupported opcode".to_string(),
2296 break Ok(Noun::Cell(Cell {
2299 t: Noun::Cell(th).into_box(),
2303 t: Cell { h: s.h, t: t.t }.tar()?.into_box(),
2309 msg: "*[a b] cannot be evaluated when b is an atom".to_string(),
2319From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
2322package object nnnock {
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)
2334 private def apply( nl : List[Noun] ) : Cell = {
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 {
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 ) => {
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) );
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
2401From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
2411 (let ((l (length a)))
2413 ((equal? l 0) (raise 1))
2414 ((equal? l 1) (r (car a)))
2417 ((equal? l 2) (cadr a))
2421 (lambda (q) (r (cons p q)))))))))))
2432 ((equal? (wut a) 0) (raise 3))
2437 ((equal? (wut a) 1) (raise 4))
2438 ((equal? (car a) (cdr a)) 0)
2443 ((equal? (wut a) 1) (raise 5))
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)))
2455 (fas (cons (div h 2) t)
2456 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
2457 (lambda (q) (r q)))))))))))
2461 ((equal? (wut a) 1) (raise 9))
2466 ((equal? (wut f) 1) (raise 10))
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))
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
2508 (list 1 (list (car y)) (list (cdr y)))
2517 (lambda (p) (r p))))
2518 (else (raise 13)))))))))))))
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.
2530// 6 :: [a b c] [a [b c]]
2534// 10 :: +[a b] +[a b]
2543// 19 :: /[(a + a) b] /[2 /[a b]]
2544// 20 :: /[(a + a + 1) b] /[3 /[a b]]
2547// 23 :: *[a [b c] d] [*[a b c] *[a d]]
2549// 25 :: *[a 0 b] /[b a]
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]
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]
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
2572 // 3 :: A cell is an ordered pair of nouns.
2573 case Cell(Noun, Noun)
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]) {
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) {
2599 // protocol ArrayLiteralConvertible
2600 public typealias Element = Noun
2601 public init(arrayLiteral elements: Element...) {
2602 self = Noun(elements)
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
2616 case let .Cell(a, b):
2617 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2623 // protocol CustomStringConvertible
2624 public var description: String {
2628 private func describe(depth: Int = 0) -> String {
2633 return "[%INVALID%]"
2634 case let .Atom(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
2671public func lus(noun: Noun) -> Noun
2673 if case let .Atom(a) = noun {
2677 // 10 :: +[a b] +[a b]
2682public func tis(noun: Noun) -> Noun
2684 if case let .Cell(a, b) = noun {
2687 return (a == b) ? Noun.YES : Noun.NO
2694public func fas(noun: Noun) -> Noun
2698 case let .Cell(1, a):
2701 case let .Cell(2, .Cell(a, _)):
2704 case let .Cell(3, .Cell(_, 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))))
2719public func tar(noun: Noun) -> Noun
2722 case let .Cell(a, 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):
2733 case let .Cell(1, 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)):
2787public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2789public func dao(formula: Noun) -> Noun->Noun
2791 if let cached = nock_functions[formula] {
2795 let compiler = { () -> Noun -> Noun in
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
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
2813 return { a in wut(f(a)) }
2815 case let .Cell(4, b): // Bump
2817 return { a in lus(f(a)) }
2819 case let .Cell(5, b): // Same
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))
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
2848 let arm = dao(fas(.Cell(b, core)))
2852 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2855 return { a in ignore(a); return f(a) }
2857 case let .Cell(10, .Cell(_, c)): // Hint
2859 return { a in f(a) }
2862 return { a in tar(.Cell(a, formula)) }
2867 nock_functions[formula] = r
2871public func nock(n: Noun) -> Noun
2873 if case let .Cell(a, b) = n {
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list