2title = "Implementations"
5insert_anchor_links = "right"
8We use a C implementation for our Nock interpreter. But building a Nock interpreter in another language is a fun exercise. Check out our community Nock implementations, shown below our official C implementation. (Note: the community implementations were written for a slightly older version of Nock, Nock 5K. The current version is Nock 4K.):
22- [JavaScript](#javascript)
36The actual production Nock interpreter. Note gotos for tail-call elimination,
37and manual reference counting. More about the C environment can be found
38in the [runtime system documentation](@/docs/tutorials/vere/runtime.md).
40/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
43_n_nock_on(u3_noun bus, u3_noun fol)
55 if ( c3y == u3r_du(hib) ) {
58 poz = _n_nock_on(u3k(bus), u3k(hib));
59 riv = _n_nock_on(bus, u3k(gal));
62 return u3i_cell(poz, riv);
65 default: return u3m_bail(c3__exit);
68 if ( c3n == u3r_ud(gal) ) {
69 return u3m_bail(c3__exit);
72 u3_noun pro = u3k(u3at(gal, bus));
74 u3a_lose(bus); u3a_lose(fol);
78 c3_assert(!"not reached");
81 u3_noun pro = u3k(gal);
83 u3a_lose(bus); u3a_lose(fol);
86 c3_assert(!"not reached");
89 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
90 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
97 c3_assert(!"not reached");
102 gof = _n_nock_on(bus, u3k(gal));
105 u3a_lose(gof); u3a_lose(fol);
108 c3_assert(!"not reached");
113 gof = _n_nock_on(bus, u3k(gal));
119 c3_assert(!"not reached");
122 u3_noun wim = _n_nock_on(bus, u3k(gal));
123 u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
125 u3a_lose(wim); u3a_lose(fol);
128 c3_assert(!"not reached");
131 u3_noun b_gal, c_gal, d_gal;
133 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
135 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
140 } else if ( 1 == tys ) {
142 } else return u3m_bail(c3__exit);
149 c3_assert(!"not reached");
152 u3_noun b_gal, c_gal;
154 u3x_cell(gal, &b_gal, &c_gal);
156 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
157 u3_noun nex = u3k(c_gal);
165 c3_assert(!"not reached");
168 u3_noun b_gal, c_gal;
170 u3x_cell(gal, &b_gal, &c_gal);
172 u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
173 u3_noun bod = u3nc(heb, bus);
174 u3_noun nex = u3k(c_gal);
182 c3_assert(!"not reached");
185 u3_noun b_gal, c_gal;
187 u3x_cell(gal, &b_gal, &c_gal);
189 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
193 pro = u3j_kick(seb, b_gal);
196 if ( u3_none != pro ) {
201 if ( c3n == u3r_ud(b_gal) ) {
202 return u3m_bail(c3__exit);
205 u3_noun nex = u3k(u3at(b_gal, seb));
215 c3_assert(!"not reached");
218 u3_noun p_gal, q_gal;
220 u3x_cell(gal, &p_gal, &q_gal);
222 u3_noun zep, hod, nex;
224 if ( c3y == u3r_du(p_gal) ) {
225 u3_noun b_gal = u3h(p_gal);
226 u3_noun c_gal = u3t(p_gal);
227 u3_noun d_gal = q_gal;
230 hod = _n_nock_on(u3k(bus), u3k(c_gal));
234 u3_noun b_gal = p_gal;
235 u3_noun c_gal = q_gal;
243 return _n_hint(zep, hod, bus, nex);
248 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
249 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
253 val = u3m_soft_esc(ref, u3k(gof));
256 if ( !_(u3du(val)) ) {
257 u3m_bail(u3nt(1, gof, 0));
259 if ( !_(u3du(u3t(val))) ) {
261 // replace with proper error stack push
263 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
264 return u3m_bail(c3__exit);
271 pro = u3k(u3t(u3t(val)));
277 c3_assert(!"not reached");
285From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
289 (:import anock.NockException))
291(declare atom? cell? cell)
294 "A noun is an atom or a cell."
297 (or (atom? noun) (cell? noun))))
300 "An atom is a natural number."
303 (and (integer? noun) (>= noun 0))))
306 "A cell is an ordered pair of nouns."
311 (not= 2 (count noun)) false
312 :else (and (noun? (first noun))
313 (noun? (second noun)))))
316 "= (pronounced 'tis') tests a cell for equality."
318 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
323 "? (pronounced 'wut') tests whether a noun is a cell."
328 :else (throw (anock.NockException. "Invalid noun."))))
331 "+ (pronounced 'lus') adds 1 to an atom."
333 (if (atom? noun) (inc noun)
334 (throw (anock.NockException. "Can only lus atoms."))))
337 "/ (pronounced 'fas') is a tree address function."
339 (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
340 (let [[a b] (cell noun)]
341 (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
342 (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
343 (throw (anock.NockException. (str "Cannot fas noun: " noun))))
348 (even? a) (fas [2 (fas [(/ a 2) b])])
349 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
352 "* (pronounced 'tar') means Nock"
354 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
356 (let [noun (cell noun) [x [y z]] noun]
358 (cell? y) (cell (tar [x y]) (tar [x z]))
359 (zero? y) (fas [z x])
361 (= 3 y) (wut (tar [x z]))
362 (= 4 y) (lus (tar [x z]))
363 (= 5 y) (tis (tar [x z]))
366 (= 2 y) (tar [(tar [x p]) (tar [x q])])
367 (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
368 [1 0] 2 [1 2 3] [1 0] 4 4 p])
369 (= 7 y) (tar [x 2 p 1 q])
370 (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
371 (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
372 (= 10 y) (if (cell? p)
373 (tar [x 8 (second p) 7 [0 3] q])
375 (catch RuntimeException e
376 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
380; Some convenience functions
382 (if (and (= 1 (count x)) (coll? (first x)))
387 "[a b c] -> [a [b c]]"
391 (and (noun? a) (apply noun? b)) (vec c)
392 (apply noun? b) (apply vector (bracket a) b)
393 (noun? a) [a (apply* bracket b)]
394 :else [(bracket a) (apply* bracket b)])))
397 (if (apply atom? nouns)
398 (throw (anock.NockException. "Cannot convert atom to cell."))
399 (apply* bracket nouns)))
404From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
408using System.Collections.Generic;
411using System.Text.RegularExpressions;
413namespace NockInterpreter
417 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
419 public static Noun Nock(Noun noun)
423 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
428 if (Atom.IsAtom(noun))
429 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
432 Noun subject = noun.n1;
433 if (Noun.IsCell(noun.n2))
435 Cell formula = (Cell)noun.n2;
436 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
438 Atom op = (Atom)formula.n1;
439 Noun operands = formula.n2;
443 case 0: // 25 :: *[a 0 b] /[b a]
444 memocache[noun.ToString()] = fas(operands, subject);
445 return memocache[noun.ToString()];
446 case 1: // 26 :: *[a 1 b] b
447 memocache[noun.ToString()] = operands;
448 return memocache[noun.ToString()];
449 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
450 if (Noun.IsCell(operands))
452 Noun a = Nock(subject, operands.n1);
453 Noun b = Nock(subject, operands.n2);
454 noun = Noun.CreateNoun(a, b);
456 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
458 throw new Exception("Atom after operand 2: " + operands.ToString());
459 case 3: // 28 :: *[a 3 b] ?*[a b]
460 memocache[noun.ToString()] = wut(Nock(subject, operands));
461 return memocache[noun.ToString()];
462 case 4: // 29 :: *[a 4 b] +*[a b]
463 memocache[noun.ToString()] = lus(Nock(subject, operands));
464 return memocache[noun.ToString()];
465 case 5: // 30 :: *[a 5 b] =*[a b]
466 memocache[noun.ToString()] = tis(Nock(subject, operands));
467 return memocache[noun.ToString()];
468 case 6: // 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
469 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
471 Noun b = operands.n1;
472 Noun c = operands.n2.n1;
473 Noun d = operands.n2.n2;
474 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
476 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
478 throw new Exception("Unhandled pattern for operand 6");
479 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
480 if (Noun.IsCell(operands))
482 Noun b = operands.n1;
483 Noun c = operands.n2;
484 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
486 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
488 throw new Exception("Atom after operand 7: " + operands.ToString());
489 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
490 if (Noun.IsCell(operands))
492 Noun b = operands.n1;
493 Noun c = operands.n2;
494 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
496 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
498 throw new Exception("Atom after operand 8: " + operands.ToString());
499 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
500 if (Noun.IsCell(operands))
502 Noun b = operands.n1;
503 Noun c = operands.n2;
504 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
506 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
508 throw new Exception("Atom after operand 9: " + operands.ToString());
510 if (Noun.IsCell(operands))
512 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
514 Noun b = operands.n1.n1;
515 Noun c = operands.n1.n2;
516 Noun d = operands.n2;
517 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
519 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
521 else // 37 :: *[a 10 b c] *[a c]
523 Noun c = operands.n2;
524 noun = Noun.CreateNoun(subject, c);
526 // return Nock(subject, c);
529 throw new Exception("Atom after operand 10: " + operands.ToString());
531 throw new Exception("Unknown operand: " + op.value);
534 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
536 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
537 return memocache[noun.ToString()];
541 throw new Exception("Unhandled pattern");
544 public static Noun Nock(string program)
546 Noun noun = Noun.CreateNoun(program);
550 public static Noun Nock(Noun n1, Noun n2)
552 Noun noun = Noun.CreateNoun(n1, n2);
556 private static Noun tis(Noun noun)
558 if (Noun.IsAtom(noun.ToString()))
559 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
562 Cell cell = (Cell)noun;
564 if (cell.n1.ToString() == cell.n2.ToString())
565 return Noun.CreateNoun("0");
567 return Noun.CreateNoun("1");
571 private static Noun lus(Noun noun)
573 if (Noun.IsAtom(noun.ToString()))
577 return Noun.CreateNoun(v.ToString());
580 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
583 private static Noun wut(Noun noun)
585 if (Noun.IsAtom(noun.ToString()))
586 return Noun.CreateNoun("1");
588 return Noun.CreateNoun("0");
591 private static Noun fas(Noun n1, Noun n2)
593 Noun noun = Noun.CreateNoun(n1, n2);
597 private static Noun fas(Noun noun)
599 if (Noun.IsAtom(noun.ToString()))
600 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
604 // If n1 isn't an atom, I assume we throw? This isn't defined in the spec. Confirmed by John B by email. This spins forever.
605 if (Noun.IsCell(c.n1.ToString()))
606 throw new Exception("Axis must be an atom: " + c.ToString());
612 else if (a.value >= 2)
614 if (!Noun.IsCell(c.n2.ToString()))
616 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
620 Cell c2 = (Cell)c.n2;
623 else if (a.value == 3)
625 else if (a.value % 2 == 0)
627 int half = a.value / 2;
628 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
630 else if (a.value % 2 == 1)
632 int half = a.value / 2;
633 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
637 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
642 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
652 // takes a program, returns a pair of nouns, stringified.
653 public static Tuple<string, string> SplitCell(string program)
658 // split the string right after the first space
659 foreach (char c in program)
669 // if we see a space, and our stack count is at 1, then we've found our split point
672 string a = program.Substring(1, i - 1);
673 string b = program.Substring(i + 1, program.Length - (i + 2));
675 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
676 if (!IsCell(b) && !IsAtom(b))
678 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
684 throw new Exception("Invalid char in cell: " + c);
687 throw new Exception("Invalid cell: " + program);
690 public static bool IsCell(string program)
692 // check if cell is valid, as above but make sure no space after bracket
693 // valid tokens are: space, int, [, ]
695 // from int => space, ], int
696 // from ] => space, ]
697 // from space => int, [
699 // stack count must always be nonzero
700 // first and last elements must be [ and ]
702 int i = 0; // i is the stack count for brackets.
704 char s = '\0'; // s is the last seen character
705 // split the string right after the first space
706 foreach (char c in program)
715 if (!(c == '[' || IsInt(c)))
720 if (!(IsInt(c) || c == ' ' || c == ']'))
725 if (!(c == ']' || c == ' '))
730 if (!(c == '[' || IsInt(c)))
739 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
743 // We should end with stack count of zero
750 public static bool IsInt(char c)
767 public static bool IsValidChar(char c)
778 public static bool IsAtom(string program)
781 if (int.TryParse(program, out i))
789 public static bool IsAtom(Noun noun)
791 return IsAtom(noun.ToString());
794 public static bool IsCell(Noun noun)
796 return IsCell(noun.ToString());
799 public static Noun CreateNoun(string program)
802 return new Atom(program);
804 return new Cell(program);
807 public static Noun CreateNoun(Noun n1, Noun n2)
809 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
812 public static Noun CreateNoun(string p1, Noun n2)
814 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
817 public static Noun CreateNoun(Noun n1, string p2)
819 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
822 public static Noun CreateNoun(string p1, string p2)
824 return CreateNoun("[" + p1 + " " + p2 + "]");
832 public override string ToString()
834 return value.ToString();
837 public Atom(string program)
842 bool result = int.TryParse(program, out i);
846 throw new ArgumentException("Invalid Atom: " + program);
854 public override string ToString()
856 return "[" + n1.ToString() + " " + n2.ToString() + "]";
859 public Cell(string program)
863 Tuple<string, string> split = SplitCell(program);
864 n1 = CreateNoun(split.Item1);
865 n2 = CreateNoun(split.Item2);
868 throw new ArgumentException("Invalid Cell: " + program);
876From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
903 } else if (a.size() >= 2) {
905 n(a.size() == 2 ? a[1] : a.tail(), { h ->
910 throw new IllegalStateException()
915 throw new IllegalStateException()
927 throw new IllegalStateException()
935 throw new IllegalStateException()
948def fas(def a, def r) {
950 throw new IllegalStateException()
954 throw new IllegalStateException()
958 throw new IllegalStateException()
963 throw new IllegalStateException()
970 fas([h.intdiv(2), t], { p ->
971 fas([2 + h.mod(2), p], { q ->
987def tar(def a, def r) {
989 throw new IllegalStateException()
994 throw new IllegalStateException()
1007 } else if (o == 1) {
1009 } else if (o == 3) {
1013 } else if (o == 4) {
1017 } else if (o == 5) {
1023 throw new IllegalStateException()
1035 } else if (o == 7) {
1036 tar(n([s, 2, x, 1, y]), {
1039 } else if (o == 8) {
1040 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1043 } else if (o == 9) {
1044 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1047 } else if (o == 10) {
1053 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1059 throw new IllegalStateException()
1062 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1066 throw new IllegalStateException()
1076From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
1079module Language.Nock5K.Spec where
1080import Control.Monad.Instances
1082wut (a :- b) = return $ Atom 0
1083wut a = return $ Atom 1
1085lus (a :- b) = Left "+[a b]"
1086lus (Atom a) = return $ Atom (1 + a)
1088tis (a :- a') | a == a' = return $ Atom 0
1089tis (a :- b) = return $ Atom 1
1092fas (Atom 1 :- a) = return a
1093fas (Atom 2 :- a :- b) = return a
1094fas (Atom 3 :- a :- b) = return b
1095fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
1096 fas $ Atom (2 + (a `mod` 2)) :- x
1099tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
1103tar (a :- Atom 0 :- b) = fas $ b :- a
1104tar (a :- Atom 1 :- b) = return b
1105tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
1108tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
1109tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
1110tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
1112tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
1113 Atom 2 :- (Atom 1 :- c :- d) :-
1114 (Atom 1 :- Atom 0) :- Atom 2 :-
1115 (Atom 1 :- Atom 2 :- Atom 3) :-
1116 (Atom 1 :- Atom 0) :- Atom 4 :-
1118tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
1119tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
1120 ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
1121 Atom 0 :- Atom 1) :- c)
1122tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
1123 (Atom 0 :- Atom 1) :- Atom 0 :- b)
1124tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
1125 (Atom 0 :- Atom 3) :- d)
1126tar (a :- Atom 10 :- b :- c) = tar (a :- c)
1138 [$(fol -.fol) $(fol +.fol)]
1145 =+ [now=(cap b.fol) lat=(mas b.fol)]
1146 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1153 $(sub -.ben, fol +.ben)
1170 $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
1172 {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
1173 {$8 b/* c/*} $(fol =>(fol [7 [[7 [0 1] b] 0 1] c]))
1174 {$9 b/* c/*} $(fol =>(fol [7 c 2 [0 1] 0 b]))
1175 {$10 @ c/*} $(fol c.fol)
1176 {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
1182From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1185(function (self, factory) {
1188 if (typeof define === 'function' && define.amd) {
1190 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1191 module.exports = factory()
1193 self.nock = factory()
1195}(this, function () {
1199 * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
1200 * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
1202 * @see http://urbit.org/docs/nock/definition/
1203 * @see https://media.urbit.org/whitepaper.pdf
1206 var useMacros = false
1212 * `s` is a subject noun,
1213 * `f` is a formula (or cell of formulas)
1219 * wut (?): test for atom (1) or cell (0)
1225 return typeof n === 'number' ? 1 : 0
1229 * lus (+): increment an atom
1235 if (wut(n) === 0) throw new Error('lus cell')
1240 * tis (=): test equality
1247 if (wut(n) === 1) throw new Error('tis atom')
1248 return deepEqual(n[0], n[1]) ? 0 : 1
1252 * fas (/): resolve a tree address
1257 * /[(a + a) b] /[2 /[a b]]
1258 * /[(a + a + 1) b] /[3 /[a b]]
1261 function fas (addr, n) {
1262 if (n === undefined) throw new Error('invalid fas noun')
1263 if (addr === 0) throw new Error('invalid fas addr: 0')
1265 if (addr === 1) return n
1266 if (addr === 2) return n[0]
1267 if (addr === 3) return n[1]
1269 return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
1275 * slot (0): resolve a tree address
1279 function slot (s, f) {
1282 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1288 * constant (1): return the formula regardless of subject
1292 function constant (s, f) {
1297 * evaluate (2): evaluate the product of second formula against the product of the first
1299 * *[a 2 b c] *[*[a b] *[a c]]
1301 function evaluate (s, f) {
1302 return nock(nock(s, f[0]), nock(s, f[1]))
1306 * cell (3): test if the product is a cell
1310 function cell (s, f) {
1311 return wut(nock(s, f))
1315 * incr (4): increment the product
1319 function incr (s, f) {
1320 return lus(nock(s, f))
1324 * eq (5): test for equality between nouns in the product
1328 function eq (s, f) {
1329 return tis(nock(s, f))
1332 /* macro-formulas */
1335 * ife (6): if/then/else
1337 * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1339 function macroIfe (s, f) {
1340 return nock(s, [2, [[0, 1], [2, [[1, [f[1][0], f[1][1]]], [[1, 0], [2, [[1, [2, 3]], [[1, 0], [4, [4, f[0]]]]]]]]]]])
1343 function ife (s, f) {
1344 var cond = nock(s, f[0])
1346 if (cond === 0) return nock(s, f[1][0])
1347 if (cond === 1) return nock(s, f[1][1])
1349 throw new Error('invalid ife conditional')
1353 * compose (7): evaluate formulas composed left-to-right
1355 * *[a 7 b c] *[a 2 b 1 c]
1357 function macroCompose (s, f) {
1358 return nock(s, [2, [f[0], [1, f[1]]]])
1361 function compose (s, f) {
1363 // return nock(nock(s, f[0]), constant(s, f[1]))
1364 return nock(nock(s, f[0]), f[1])
1368 * extend (8): evaluate the second formula against [product of first, subject]
1370 * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
1372 function macroExtend (s, f) {
1373 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1376 function extend (s, f) {
1378 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1379 return nock([nock(s, f[0]), s], f[1])
1383 * invoke (9): construct a core and evaluate one of its arms against it
1385 * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
1387 function macroInvoke (s, f) {
1388 return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
1391 function invoke (s, f) {
1392 var prod = nock(s, f[1])
1393 return nock(prod, slot(prod, f[0]))
1397 * hint (10): skip first formula, evaluate second
1399 * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
1400 * *[a 10 b c] *[a c]
1402 function macroHint (s, f) {
1403 if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
1404 return nock(s, f[1])
1407 function hint (s, f) {
1408 if (wut(f[0]) === 0) {
1409 if (wut(f[0][1]) === 1) throw new Error('invalid hint')
1412 return nock(s, f[1])
1415 /* indexed formula functions */
1416 var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
1417 var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
1424 * *[a [b c] d] [*[a b c] *[a d]]
1427 function nock (s, f) {
1428 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
1432 if (idx > 10) throw new Error('invalid formula: ' + idx)
1434 if (useMacros) return macroFormulas[idx](s, f[1])
1436 return formulas[idx](s, f[1])
1439 /* construct a JS noun (group an array into pairs, associating right) */
1440 function assoc (x) {
1441 if (!x.length) return x
1443 if (x.length === 1) return assoc(x[0])
1445 return [assoc(x[0]), assoc(x.slice(1))]
1448 /* deep equality for arrays or primitives */
1449 function deepEqual (a, b) {
1450 if (a === b) return true
1452 if (!(Array.isArray(a) && Array.isArray(b))) return false
1453 if (a.length !== b.length) return false
1455 for (var i = 0; i < a.length; i++) {
1456 if (!deepEqual(a[i], b[i])) return false
1462 /* parse a hoon-serialized nock formula and construct a JS noun */
1463 function parseNoun (x) {
1464 if (Array.isArray(x)) return assoc(x)
1466 if (typeof x === 'string') {
1467 var str = x.replace(/[\."']/g, '').split(' ').join(',')
1468 return assoc(JSON.parse(str))
1474 function nockInterface () {
1475 var args = [].slice.call(arguments)
1476 var subject, formula, noun
1478 if (args.length === 1) {
1479 formula = parseNoun(args[0])
1480 } else if (args.length === 2) {
1481 subject = parseNoun(args[0])
1482 formula = parseNoun(args[1])
1489 if (!formula) throw new Error('formula required')
1496 return nock(subject, formula)
1500 nock: nockInterface,
1502 useMacros: function (arg) {
1503 useMacros = arg === undefined || arg
1508 parseNoun: parseNoun,
1509 deepEqual: deepEqual
1526 macroCompose: macroCompose,
1528 macroExtend: macroExtend,
1530 macroInvoke: macroInvoke,
1532 macroHint: macroHint,
1541From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1544#!/usr/bin/env python3
1553 return (lst[0], l(*lst[1:]))
1561 if isinstance(noun, int):
1569 if isinstance(noun, int):
1577 if noun[0] == noun[1]:
1591 elif noun[0] % 2 == 0:
1592 return slot((2, slot((noun[0] // 2, noun[1]))))
1593 elif noun[0] % 2 == 1:
1594 return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
1598 if isinstance(noun[1][0], int):
1600 return slot((noun[1][1], noun[0]))
1601 elif noun[1][0] == 1:
1603 elif noun[1][0] == 2:
1604 return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
1605 elif noun[1][0] == 3:
1606 return wut(nock((noun[0], noun[1][1])))
1607 elif noun[1][0] == 4:
1608 return lus(nock((noun[0], noun[1][1])))
1609 elif noun[1][0] == 5:
1610 return tis(nock((noun[0], noun[1][1])))
1611 elif noun[1][0] == 6:
1612 return nock(l(noun[0], 2, (0, 1), 2, l(1, noun[1][1][1][0], noun[1][1][1][1]), (1, 0), 2, l(1, 2, 3), (1, 0), 4, 4, noun[1][1][0]))
1613 elif noun[1][0] == 7:
1614 return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
1615 elif noun[1][0] == 8:
1616 return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
1617 elif noun[1][0] == 9:
1618 return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
1619 elif noun[1][0] == 10:
1620 if isinstance(noun[1][1][0], int):
1621 return nock((noun[0], noun[1][1][1]))
1623 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1625 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1630From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1635 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1640 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1645 depth = max_depth(arr)
1647 1.up_to(8) do |depth|
1649 min = 2 ** (depth - 1)
1650 max = (2 ** depth) - 1
1651 min.upto(max) { |axis|
1657 return arr unless arr.is_a?(Array)
1660 arr[size - 2] = [ arr[size - 2], arr.pop ]
1662 arr = arr.map { |x| norm(x) }
1666 arr.is_a?(Array) ? YES : NO
1670 raise "not an atom" unless atom.is_a?(Fixnum)
1675 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1676 ( arr[0] == arr[1] ) ? YES : NO
1679def slot(axis, arr, allow_error = true)
1680 raise "axis on atom" unless arr.is_a?(Array)
1681 return arr if axis == 1
1682 return arr[0] if axis == 2
1683 return arr[1] if axis == 3
1684 return slot(2, slot(axis/2, arr)) if (axis %2) == 0
1685 return slot(3, slot(axis/2, arr))
1690 raise "error: nocking an atom" unless arr.is_a?(Array)
1696 if oper.is_a?(Array)
1697 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1709 b_prime = slot(2, b)
1711 nock( [ nock([a, b_primce]), nock([a, c]) ])
1723 b_prime = slot(2, b)
1726 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1729 b_prime = slot(2, b)
1731 nock( norm ([a, 2, b_prime, 1, c]))
1734 b_prime = slot(2, b)
1736 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1739 b_prime = slot(2, b)
1741 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1744 if wut(slot(2,b)) == TRUE
1745 b_prime = slot(4, b)
1749 nock( norm ([a, 8, c, 7, [0, 3], d]))
1751 b_prime = slot(2, b)
1753 nock( norm ([a, 10, [b, c]]))
1756 raise "error: unknown opcode #{oper.inspect}"
1763From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
1766package object nnnock {
1769 case class Atom( value : Int ) extends Noun;
1770 case class Cell( head : Noun, tail : Noun ) extends Noun;
1771 implicit def toAtom( value : Int ) : Atom = Atom( value );
1772 implicit def toInt( atom : Atom ) : Int = atom.value;
1774 def nock( a : Noun ) : Noun = *(a)
1778 private def apply( nl : List[Noun] ) : Cell = {
1780 case a :: b :: Nil => Cell(a, b);
1781 case a :: b :: c :: Nil => Cell(a, Cell(b, c));
1782 case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
1785 def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
1788 def ?( noun : Noun ) : Noun = noun match {
1793 @tailrec def plus( noun : Noun ) : Noun = noun match {
1794 case a : Atom => 1 + a;
1795 case c : Cell => plus( c ); //intentional endless spin
1798 def heq( noun : Noun ) : Atom = noun match {
1799 case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
1800 case Cell( a : Cell, b : Atom ) => 1;
1801 case Cell( a : Atom, b : Cell ) => 1;
1802 case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
1803 case a : Atom => heq( a ); //intentional endless spin
1806 def /( noun : Noun ) : Noun = noun match {
1807 case Cell(Atom(1), a) => a;
1808 case Cell(Atom(2), Cell(a, b)) => a;
1809 case Cell(Atom(3), Cell(a, b)) => b;
1810 case Cell(Atom(value), b ) => {
1812 val num = if ( value % a == 0 ) 2 else 3;
1813 /(Cell(num, /(Cell(a, b))));
1815 case a => /( a ); //intentional endless spin
1819 def *( noun : Noun ) : Noun = noun match {
1820 case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
1821 case Cell( a, Cell(Atom(value), tail) ) => {
1822 (value, tail) match {
1823 case (0, b) => /( Cell(b, a) );
1825 case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
1826 case (3, b) => ?( *( Cell(a,b) ) );
1827 case (4, b) => plus( *( Cell(a,b) ) );
1828 case (5, b) => heq( *( Cell(a,b) ) );
1829 case (6, Cell(b, Cell(c, d))) => *( Cell(a,2,Cell(0,1),2,Cell(1,c,d),Cell(1,0),2,Cell(1,2,3),Cell(1,0),4,4,b) ); //wtf?
1830 case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
1831 case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
1832 case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
1833 case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
1834 case (10, Cell(b, c)) => *( Cell(a,c) );
1835 case _ => *( noun ); //intentional endless spin
1838 case a => *( a ); //intentional endless spin
1845From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
1855 (let ((l (length a)))
1857 ((equal? l 0) (raise 1))
1858 ((equal? l 1) (r (car a)))
1861 ((equal? l 2) (cadr a))
1865 (lambda (q) (r (cons p q)))))))))))
1876 ((equal? (wut a) 0) (raise 3))
1881 ((equal? (wut a) 1) (raise 4))
1882 ((equal? (car a) (cdr a)) 0)
1887 ((equal? (wut a) 1) (raise 5))
1892 ((not (fixnum? h)) (raise 6))
1893 ((equal? h 0) (raise 7))
1894 ((equal? h 1) (r t))
1895 ((fixnum? t) (raise 8))
1896 ((equal? h 2) (r (car t)))
1897 ((equal? h 3) (r (cdr t)))
1899 (fas (cons (div h 2) t)
1900 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
1901 (lambda (q) (r q)))))))))))
1905 ((equal? (wut a) 1) (raise 9))
1910 ((equal? (wut f) 1) (raise 10))
1915 ((equal? (wut o) 0) (tar (cons s o)
1916 (lambda (p) (tar (cons s v)
1917 (lambda (q) (r (cons p q)))))))
1918 ((equal? o 0) (r (fas (cons v s) i)))
1919 ((equal? o 1) (r v))
1920 ((equal? o 3) (tar (cons s v)
1921 (lambda (p) (r (wut p)))))
1922 ((equal? o 4) (tar (cons s v)
1923 (lambda (p) (r (lus p)))))
1924 ((equal? o 5) (tar (cons s v)
1925 (lambda (p) (r (tis p)))))
1926 ((equal? (wut v) 1) (raise 11))
1931 ((equal? o 2) (tar (cons s x)
1932 (lambda (p) (tar (cons s y)
1933 (lambda (q) (tar (cons p q)
1934 (lambda (u) (r u))))))))
1935 ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
1936 (lambda (p) (r p))))
1937 ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
1938 (lambda (p) (r p))))
1939 ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
1940 (lambda (p) (r p))))
1941 ((equal? o 10) (cond
1942 ((equal? (wut x) 1) (tar (cons s y)
1943 (lambda (p) (r p))))
1944 (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
1945 (lambda (p) (r p))))))
1946 ((equal? (wut y) 1) (raise 12))
1947 ((equal? o 6) (tar (n (list
1952 (list 1 (list (car y)) (list (cdr y)))
1961 (lambda (p) (r p))))
1962 (else (raise 13)))))))))))))
1969// 1 :: A noun is an atom or a cell.
1970// 2 :: An atom is a natural number.
1971// 3 :: A cell is an ordered pair of nouns.
1974// 6 :: [a b c] [a [b c]]
1978// 10 :: +[a b] +[a b]
1987// 19 :: /[(a + a) b] /[2 /[a b]]
1988// 20 :: /[(a + a + 1) b] /[3 /[a b]]
1991// 23 :: *[a [b c] d] [*[a b c] *[a d]]
1993// 25 :: *[a 0 b] /[b a]
1995// 27 :: *[a 2 b c] *[*[a b] *[a c]]
1996// 28 :: *[a 3 b] ?*[a b]
1997// 29 :: *[a 4 b] +*[a b]
1998// 30 :: *[a 5 b] =*[a b]
2000// 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
2001// 33 :: *[a 7 b c] *[a 2 b 1 c]
2002// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2003// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2004// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2005// 37 :: *[a 10 b c] *[a c]
2009// 1 :: A noun is an atom or a cell.
2010public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
2012 // 2 :: An atom is a natural number.
2013 public typealias ATOM = UIntMax
2016 // 3 :: A cell is an ordered pair of nouns.
2017 case Cell(Noun, Noun)
2020 public static var YES: Noun { return .Atom(0) }
2021 public static var NO: Noun { return .Atom(1) }
2023 public init(_ noun: Noun) { self = noun }
2025 // 6 :: [a b c] [a [b c]]
2026 public init(_ nouns: [Noun]) {
2028 if nouns.count > 0 {
2029 var reverse = nouns.reverse().generate()
2030 self = reverse.next()!
2031 while let n = reverse.next() {
2032 self = .Cell(n, self)
2037 // protocol IntegerLiteralConvertible
2038 public typealias IntegerLiteralType = ATOM
2039 public init(integerLiteral value: IntegerLiteralType) {
2043 // protocol ArrayLiteralConvertible
2044 public typealias Element = Noun
2045 public init(arrayLiteral elements: Element...) {
2046 self = Noun(elements)
2050 public subscript(axis: ATOM) -> Noun {
2051 return fas(.Cell(.Atom(axis), self))
2054 // protocol Hashable
2055 public var hashValue: Int {
2056 //return self.description.hashValue
2060 case let .Cell(a, b):
2061 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2067 // protocol CustomStringConvertible
2068 public var description: String {
2072 private func describe(depth: Int = 0) -> String {
2077 return "[%INVALID%]"
2078 case let .Atom(atom):
2080 case let .Cell(.Cell(a, b), c):
2081 sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
2082 case let .Cell(a, b):
2083 sub = "\(a.describe(next)) \(b.describe(next))"
2085 return depth == 0 ? "[\(sub)]" : sub
2089// protocol Equatable
2090public func == (left: Noun, right: Noun) -> Bool
2092 switch (left, right) {
2093 case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
2094 case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
2095 case (.Invalid, .Invalid): return true
2096 default: return false
2100public func wut(noun: Noun) -> Noun
2115public func lus(noun: Noun) -> Noun
2117 if case let .Atom(a) = noun {
2121 // 10 :: +[a b] +[a b]
2126public func tis(noun: Noun) -> Noun
2128 if case let .Cell(a, b) = noun {
2131 return (a == b) ? Noun.YES : Noun.NO
2138public func fas(noun: Noun) -> Noun
2142 case let .Cell(1, a):
2145 case let .Cell(2, .Cell(a, _)):
2148 case let .Cell(3, .Cell(_, b)):
2150 // 19 :: /[(a + a) b] /[2 /[a b]]
2151 // 20 :: /[(a + a + 1) b] /[3 /[a b]]
2152 case let .Cell(.Atom(axis), tree):
2153 let inner = Noun.Atom(axis / 2)
2154 let outer = Noun.Atom(2 + (axis % 2))
2155 return fas(.Cell(outer, fas(.Cell(inner, tree))))
2163public func tar(noun: Noun) -> Noun
2166 case let .Cell(a, formula):
2168 // 23 :: *[a [b c] d] [*[a b c] *[a d]]
2169 case let .Cell(.Cell(b, c), d):
2170 return .Cell(tar([a, b, c]), tar([a, d]))
2172 // 25 :: *[a 0 b] /[b a]
2173 case let .Cell(0, b):
2177 case let .Cell(1, b):
2180 // 27 :: *[a 2 b c] *[*[a b] *[a c]]
2181 case let .Cell(2, .Cell(b, c)):
2182 return tar([tar([a, b]), tar([a, c])])
2184 // 28 :: *[a 3 b] ?*[a b]
2185 case let .Cell(3, b):
2186 return wut(tar([a, b]))
2188 // 29 :: *[a 4 b] +*[a b]
2189 case let .Cell(4, b):
2190 return lus(tar([a, b]))
2192 // 30 :: *[a 5 b] =*[a b]
2193 case let .Cell(5, b):
2194 return tis(tar([a, b]))
2196 // 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
2197 case let .Cell(6, .Cell(b, .Cell(c, d))):
2198 return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
2200 // 33 :: *[a 7 b c] *[a 2 b 1 c]
2201 case let .Cell(7, .Cell(b, c)):
2202 return tar([a, 2, b, 1, c])
2204 // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2205 case let .Cell(8, .Cell(b, c)):
2206 return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
2208 // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2209 case let .Cell(9, .Cell(b, c)):
2210 return tar([a, 7, c, 2, [0, 1], 0, b])
2212 // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2213 case let .Cell(10, .Cell(.Cell(_, c), d)):
2214 return tar([a, 8, c, 7, [0, 3], d])
2216 // 37 :: *[a 10 b c] *[a c]
2217 case let .Cell(10, .Cell(_, c)):
2231public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2233public func dao(formula: Noun) -> Noun->Noun
2235 if let cached = nock_functions[formula] {
2239 let compiler = { () -> Noun -> Noun in
2241 case let .Cell(.Cell(b, c), d): // Distribution
2242 let (p, q) = (dao(.Cell(b, c)), dao(d))
2243 return { a in .Cell(p(a), q(a)) }
2245 case let .Cell(0, b): // Axis
2246 return { a in fas(.Cell(b, a)) }
2248 case let .Cell(1, b): // Just
2251 case let .Cell(2, .Cell(b, c)): // Fire
2252 let (f, g) = (dao(b), dao(c))
2253 return { a in dao(g(a))(f(a)) }
2255 case let .Cell(3, b): // Depth
2257 return { a in wut(f(a)) }
2259 case let .Cell(4, b): // Bump
2261 return { a in lus(f(a)) }
2263 case let .Cell(5, b): // Same
2265 return { a in tis(f(a)) }
2267 case let .Cell(6, .Cell(b, .Cell(c, d))): // If
2268 let (p, q, r) = (dao(b), dao(c), dao(d))
2276 return tar(.Cell(a, formula))
2280 case let .Cell(7, .Cell(b, c)): // Compose
2281 let (f, g) = (dao(b), dao(c))
2282 return { a in g(f(a)) }
2284 case let .Cell(8, .Cell(b, c)): // Push
2285 let (f, g) = (dao(b), dao(c))
2286 return { a in g(.Cell(f(a), a)) }
2288 case let .Cell(9, .Cell(b, c)): // Call
2292 let arm = dao(fas(.Cell(b, core)))
2296 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2299 return { a in ignore(a); return f(a) }
2301 case let .Cell(10, .Cell(_, c)): // Hint
2303 return { a in f(a) }
2306 return { a in tar(.Cell(a, formula)) }
2311 nock_functions[formula] = r
2315public func nock(n: Noun) -> Noun
2317 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