2title = "Implementations"
6We use a C implementation for our Nock interpreter. But building a Nock interpreter in another language is a fun exercise. Check out our community Nock implementations, shown below our official C implementation. (Note: the community implementations were written for a slightly older version of Nock, Nock 5K. The current version is Nock 4K.):
20- [JavaScript](#javascript)
34The actual production Nock interpreter. Note gotos for tail-call elimination,
35and manual reference counting. More about the C environment can be found
36in the [runtime system documentation](@/docs/vere/runtime.md).
38/* _n_nock_on(): produce .*(bus fol). Do not virtualize.
41_n_nock_on(u3_noun bus, u3_noun fol)
53 if ( c3y == u3r_du(hib) ) {
56 poz = _n_nock_on(u3k(bus), u3k(hib));
57 riv = _n_nock_on(bus, u3k(gal));
60 return u3i_cell(poz, riv);
63 default: return u3m_bail(c3__exit);
66 if ( c3n == u3r_ud(gal) ) {
67 return u3m_bail(c3__exit);
70 u3_noun pro = u3k(u3at(gal, bus));
72 u3a_lose(bus); u3a_lose(fol);
76 c3_assert(!"not reached");
79 u3_noun pro = u3k(gal);
81 u3a_lose(bus); u3a_lose(fol);
84 c3_assert(!"not reached");
87 u3_noun nex = _n_nock_on(u3k(bus), u3k(u3t(gal)));
88 u3_noun seb = _n_nock_on(bus, u3k(u3h(gal)));
95 c3_assert(!"not reached");
100 gof = _n_nock_on(bus, u3k(gal));
103 u3a_lose(gof); u3a_lose(fol);
106 c3_assert(!"not reached");
111 gof = _n_nock_on(bus, u3k(gal));
117 c3_assert(!"not reached");
120 u3_noun wim = _n_nock_on(bus, u3k(gal));
121 u3_noun pro = u3r_sing(u3h(wim), u3t(wim));
123 u3a_lose(wim); u3a_lose(fol);
126 c3_assert(!"not reached");
129 u3_noun b_gal, c_gal, d_gal;
131 u3x_trel(gal, &b_gal, &c_gal, &d_gal);
133 u3_noun tys = _n_nock_on(u3k(bus), u3k(b_gal));
138 } else if ( 1 == tys ) {
140 } else return u3m_bail(c3__exit);
147 c3_assert(!"not reached");
150 u3_noun b_gal, c_gal;
152 u3x_cell(gal, &b_gal, &c_gal);
154 u3_noun bod = _n_nock_on(bus, u3k(b_gal));
155 u3_noun nex = u3k(c_gal);
163 c3_assert(!"not reached");
166 u3_noun b_gal, c_gal;
168 u3x_cell(gal, &b_gal, &c_gal);
170 u3_noun heb = _n_nock_on(u3k(bus), u3k(b_gal));
171 u3_noun bod = u3nc(heb, bus);
172 u3_noun nex = u3k(c_gal);
180 c3_assert(!"not reached");
183 u3_noun b_gal, c_gal;
185 u3x_cell(gal, &b_gal, &c_gal);
187 u3_noun seb = _n_nock_on(bus, u3k(c_gal));
191 pro = u3j_kick(seb, b_gal);
194 if ( u3_none != pro ) {
199 if ( c3n == u3r_ud(b_gal) ) {
200 return u3m_bail(c3__exit);
203 u3_noun nex = u3k(u3at(b_gal, seb));
213 c3_assert(!"not reached");
216 u3_noun p_gal, q_gal;
218 u3x_cell(gal, &p_gal, &q_gal);
220 u3_noun zep, hod, nex;
222 if ( c3y == u3r_du(p_gal) ) {
223 u3_noun b_gal = u3h(p_gal);
224 u3_noun c_gal = u3t(p_gal);
225 u3_noun d_gal = q_gal;
228 hod = _n_nock_on(u3k(bus), u3k(c_gal));
232 u3_noun b_gal = p_gal;
233 u3_noun c_gal = q_gal;
241 return _n_hint(zep, hod, bus, nex);
246 u3_noun ref = _n_nock_on(u3k(bus), u3k(u3h(gal)));
247 u3_noun gof = _n_nock_on(bus, u3k(u3t(gal)));
251 val = u3m_soft_esc(ref, u3k(gof));
254 if ( !_(u3du(val)) ) {
255 u3m_bail(u3nt(1, gof, 0));
257 if ( !_(u3du(u3t(val))) ) {
259 // replace with proper error stack push
261 u3t_push(u3nc(c3__hunk, _n_mush(gof)));
262 return u3m_bail(c3__exit);
269 pro = u3k(u3t(u3t(val)));
275 c3_assert(!"not reached");
283From [Matt Earnshaw](https://github.com/mattearnshaw/anock/blob/master/src/anock/core.clj):
287 (:import anock.NockException))
289(declare atom? cell? cell)
292 "A noun is an atom or a cell."
295 (or (atom? noun) (cell? noun))))
298 "An atom is a natural number."
301 (and (integer? noun) (>= noun 0))))
304 "A cell is an ordered pair of nouns."
309 (not= 2 (count noun)) false
310 :else (and (noun? (first noun))
311 (noun? (second noun)))))
314 "= (pronounced 'tis') tests a cell for equality."
316 (if (atom? noun) (throw (anock.NockException. "Cannot tis an atom."))
321 "? (pronounced 'wut') tests whether a noun is a cell."
326 :else (throw (anock.NockException. "Invalid noun."))))
329 "+ (pronounced 'lus') adds 1 to an atom."
331 (if (atom? noun) (inc noun)
332 (throw (anock.NockException. "Can only lus atoms."))))
335 "/ (pronounced 'fas') is a tree address function."
337 (if (atom? noun) (throw (anock.NockException. "Cannot fas an atom."))
338 (let [[a b] (cell noun)]
339 (assert (and (pos? a) (atom? a)) "Subject of fas must be a positive atom.")
340 (if (and (not (coll? b)) (or (= 2 a) (= 3 a)))
341 (throw (anock.NockException. (str "Cannot fas noun: " noun))))
346 (even? a) (fas [2 (fas [(/ a 2) b])])
347 (odd? a) (fas [3 (fas [(/ (dec a) 2) b])])))))
350 "* (pronounced 'tar') means Nock"
352 (if (atom? noun) (throw (anock.NockException. "Cannot tar an atom."))
354 (let [noun (cell noun) [x [y z]] noun]
356 (cell? y) (cell (tar [x y]) (tar [x z]))
357 (zero? y) (fas [z x])
359 (= 3 y) (wut (tar [x z]))
360 (= 4 y) (lus (tar [x z]))
361 (= 5 y) (tis (tar [x z]))
364 (= 2 y) (tar [(tar [x p]) (tar [x q])])
365 (= 6 y) (tar [x 2 [0 1] 2 [1 (first q) (second q)]
366 [1 0] 2 [1 2 3] [1 0] 4 4 p])
367 (= 7 y) (tar [x 2 p 1 q])
368 (= 8 y) (tar [x 7 [[7 [0 1] p] 0 1] q])
369 (= 9 y) (tar [x 7 q 2 [0 1] 0 p])
370 (= 10 y) (if (cell? p)
371 (tar [x 8 (second p) 7 [0 3] q])
373 (catch RuntimeException e
374 (throw (anock.NockException. (str "Cannot tar the noun " noun)))))))
378; Some convenience functions
380 (if (and (= 1 (count x)) (coll? (first x)))
385 "[a b c] -> [a [b c]]"
389 (and (noun? a) (apply noun? b)) (vec c)
390 (apply noun? b) (apply vector (bracket a) b)
391 (noun? a) [a (apply* bracket b)]
392 :else [(bracket a) (apply* bracket b)])))
395 (if (apply atom? nouns)
396 (throw (anock.NockException. "Cannot convert atom to cell."))
397 (apply* bracket nouns)))
402From [Julien Beasley](https://github.com/zass30/Nock5KCSharp):
406using System.Collections.Generic;
409using System.Text.RegularExpressions;
411namespace NockInterpreter
415 static Dictionary<string, Noun> memocache = new Dictionary<string, Noun>();
417 public static Noun Nock(Noun noun)
421 if (memocache.TryGetValue(noun.ToString(), out cache_noun))
426 if (Atom.IsAtom(noun))
427 throw new Exception("Infinite loop nocking an atom: " + noun.ToString());
430 Noun subject = noun.n1;
431 if (Noun.IsCell(noun.n2))
433 Cell formula = (Cell)noun.n2;
434 if (Noun.IsAtom(formula.n1)) // we have lines 25-37 of spec
436 Atom op = (Atom)formula.n1;
437 Noun operands = formula.n2;
441 case 0: // 25 :: *[a 0 b] /[b a]
442 memocache[noun.ToString()] = fas(operands, subject);
443 return memocache[noun.ToString()];
444 case 1: // 26 :: *[a 1 b] b
445 memocache[noun.ToString()] = operands;
446 return memocache[noun.ToString()];
447 case 2: // 27 :: *[a 2 b c] *[*[a b] *[a c]]
448 if (Noun.IsCell(operands))
450 Noun a = Nock(subject, operands.n1);
451 Noun b = Nock(subject, operands.n2);
452 noun = Noun.CreateNoun(a, b);
454 // return Nock(Nock(subject, operands.n1), Nock(subject, operands.n2));
456 throw new Exception("Atom after operand 2: " + operands.ToString());
457 case 3: // 28 :: *[a 3 b] ?*[a b]
458 memocache[noun.ToString()] = wut(Nock(subject, operands));
459 return memocache[noun.ToString()];
460 case 4: // 29 :: *[a 4 b] +*[a b]
461 memocache[noun.ToString()] = lus(Nock(subject, operands));
462 return memocache[noun.ToString()];
463 case 5: // 30 :: *[a 5 b] =*[a b]
464 memocache[noun.ToString()] = tis(Nock(subject, operands));
465 return memocache[noun.ToString()];
466 case 6: // 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
467 if (Noun.IsCell(operands) && Noun.IsCell(operands.n2))
469 Noun b = operands.n1;
470 Noun c = operands.n2.n1;
471 Noun d = operands.n2.n2;
472 noun = Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]");
474 // return Nock(Noun.CreateNoun("[" + subject + " 2 [0 1] 2 [1 " + c + " " + d + "] [1 0] 2 [1 2 3] [1 0] 4 4 " + b + "]"));
476 throw new Exception("Unhandled pattern for operand 6");
477 case 7: // 33 :: *[a 7 b c] *[a 2 b 1 c]
478 if (Noun.IsCell(operands))
480 Noun b = operands.n1;
481 Noun c = operands.n2;
482 noun = Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]");
484 // return Nock(Noun.CreateNoun("[" + subject + " 2 " + b + " 1 " + c + "]"));
486 throw new Exception("Atom after operand 7: " + operands.ToString());
487 case 8: // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
488 if (Noun.IsCell(operands))
490 Noun b = operands.n1;
491 Noun c = operands.n2;
492 noun = Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]");
494 // return Nock(Noun.CreateNoun("[" + subject + " 7 [[7 [0 1] " + b + "] 0 1] " + c + "]"));
496 throw new Exception("Atom after operand 8: " + operands.ToString());
497 case 9: // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
498 if (Noun.IsCell(operands))
500 Noun b = operands.n1;
501 Noun c = operands.n2;
502 noun = Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]");
504 // return Nock(Noun.CreateNoun("[" + subject + " 7 " + c + " 2 [0 1] 0 " + b + "]"));
506 throw new Exception("Atom after operand 9: " + operands.ToString());
508 if (Noun.IsCell(operands))
510 if (Noun.IsCell(operands.n1)) // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
512 Noun b = operands.n1.n1;
513 Noun c = operands.n1.n2;
514 Noun d = operands.n2;
515 noun = Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]");
517 // return Nock(Noun.CreateNoun("[" + subject + " 8 " + c + " 7 [0 3] " + d + "]"));
519 else // 37 :: *[a 10 b c] *[a c]
521 Noun c = operands.n2;
522 noun = Noun.CreateNoun(subject, c);
524 // return Nock(subject, c);
527 throw new Exception("Atom after operand 10: " + operands.ToString());
529 throw new Exception("Unknown operand: " + op.value);
532 else // 23 :: *[a [b c] d] [*[a b c] *[a d]]
534 memocache[noun.ToString()] = Noun.CreateNoun(Nock(subject, formula.n1), Nock(subject, formula.n2));
535 return memocache[noun.ToString()];
539 throw new Exception("Unhandled pattern");
542 public static Noun Nock(string program)
544 Noun noun = Noun.CreateNoun(program);
548 public static Noun Nock(Noun n1, Noun n2)
550 Noun noun = Noun.CreateNoun(n1, n2);
554 private static Noun tis(Noun noun)
556 if (Noun.IsAtom(noun.ToString()))
557 throw new Exception("Infinite loop tising an atom: " + noun.ToString());
560 Cell cell = (Cell)noun;
562 if (cell.n1.ToString() == cell.n2.ToString())
563 return Noun.CreateNoun("0");
565 return Noun.CreateNoun("1");
569 private static Noun lus(Noun noun)
571 if (Noun.IsAtom(noun.ToString()))
575 return Noun.CreateNoun(v.ToString());
578 throw new Exception("Infinite loop lusing a cell: " + noun.ToString());
581 private static Noun wut(Noun noun)
583 if (Noun.IsAtom(noun.ToString()))
584 return Noun.CreateNoun("1");
586 return Noun.CreateNoun("0");
589 private static Noun fas(Noun n1, Noun n2)
591 Noun noun = Noun.CreateNoun(n1, n2);
595 private static Noun fas(Noun noun)
597 if (Noun.IsAtom(noun.ToString()))
598 throw new Exception("Infinite loop fasing an atom: " + noun.ToString());
602 // If n1 isn't an atom, I assume we throw? This isn't defined in the spec. Confirmed by John B by email. This spins forever.
603 if (Noun.IsCell(c.n1.ToString()))
604 throw new Exception("Axis must be an atom: " + c.ToString());
610 else if (a.value >= 2)
612 if (!Noun.IsCell(c.n2.ToString()))
614 throw new Exception("Only a cell can have an axis of 2 or 3: " + c.n2.ToString());
618 Cell c2 = (Cell)c.n2;
621 else if (a.value == 3)
623 else if (a.value % 2 == 0)
625 int half = a.value / 2;
626 return fas(Noun.CreateNoun("2", fas(Noun.CreateNoun(half.ToString(), c2))));
628 else if (a.value % 2 == 1)
630 int half = a.value / 2;
631 return fas(Noun.CreateNoun("3", fas(Noun.CreateNoun(half.ToString(), c2))));
635 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
640 throw new Exception("Infinite loop somewhere in fasing: " + c.n2.ToString());
650 // takes a program, returns a pair of nouns, stringified.
651 public static Tuple<string, string> SplitCell(string program)
656 // split the string right after the first space
657 foreach (char c in program)
667 // if we see a space, and our stack count is at 1, then we've found our split point
670 string a = program.Substring(1, i - 1);
671 string b = program.Substring(i + 1, program.Length - (i + 2));
673 // to implement proper bracket closing, surround b with brackets if it isn't a cell and isn't an atom
674 if (!IsCell(b) && !IsAtom(b))
676 Tuple<string, string> tuple = new Tuple<string, string>(a, b);
682 throw new Exception("Invalid char in cell: " + c);
685 throw new Exception("Invalid cell: " + program);
688 public static bool IsCell(string program)
690 // check if cell is valid, as above but make sure no space after bracket
691 // valid tokens are: space, int, [, ]
693 // from int => space, ], int
694 // from ] => space, ]
695 // from space => int, [
697 // stack count must always be nonzero
698 // first and last elements must be [ and ]
700 int i = 0; // i is the stack count for brackets.
702 char s = '\0'; // s is the last seen character
703 // split the string right after the first space
704 foreach (char c in program)
713 if (!(c == '[' || IsInt(c)))
718 if (!(IsInt(c) || c == ' ' || c == ']'))
723 if (!(c == ']' || c == ' '))
728 if (!(c == '[' || IsInt(c)))
737 if (i <= 0 && counter != program.Length) // stack count can't be zero unless it's the last character
741 // We should end with stack count of zero
748 public static bool IsInt(char c)
765 public static bool IsValidChar(char c)
776 public static bool IsAtom(string program)
779 if (int.TryParse(program, out i))
787 public static bool IsAtom(Noun noun)
789 return IsAtom(noun.ToString());
792 public static bool IsCell(Noun noun)
794 return IsCell(noun.ToString());
797 public static Noun CreateNoun(string program)
800 return new Atom(program);
802 return new Cell(program);
805 public static Noun CreateNoun(Noun n1, Noun n2)
807 return CreateNoun("[" + n1.ToString() + " " + n2.ToString() + "]");
810 public static Noun CreateNoun(string p1, Noun n2)
812 return CreateNoun("[" + p1 + " " + n2.ToString() + "]");
815 public static Noun CreateNoun(Noun n1, string p2)
817 return CreateNoun("[" + n1.ToString() + " " + p2 + "]");
820 public static Noun CreateNoun(string p1, string p2)
822 return CreateNoun("[" + p1 + " " + p2 + "]");
830 public override string ToString()
832 return value.ToString();
835 public Atom(string program)
840 bool result = int.TryParse(program, out i);
844 throw new ArgumentException("Invalid Atom: " + program);
852 public override string ToString()
854 return "[" + n1.ToString() + " " + n2.ToString() + "]";
857 public Cell(string program)
861 Tuple<string, string> split = SplitCell(program);
862 n1 = CreateNoun(split.Item1);
863 n2 = CreateNoun(split.Item2);
866 throw new ArgumentException("Invalid Cell: " + program);
874From [Kohányi Róbert](https://github.com/kohanyirobert/gnock/blob/master/gnock.groovy):
901 } else if (a.size() >= 2) {
903 n(a.size() == 2 ? a[1] : a.tail(), { h ->
908 throw new IllegalStateException()
913 throw new IllegalStateException()
925 throw new IllegalStateException()
933 throw new IllegalStateException()
946def fas(def a, def r) {
948 throw new IllegalStateException()
952 throw new IllegalStateException()
956 throw new IllegalStateException()
961 throw new IllegalStateException()
968 fas([h.intdiv(2), t], { p ->
969 fas([2 + h.mod(2), p], { q ->
985def tar(def a, def r) {
987 throw new IllegalStateException()
992 throw new IllegalStateException()
1005 } else if (o == 1) {
1007 } else if (o == 3) {
1011 } else if (o == 4) {
1015 } else if (o == 5) {
1021 throw new IllegalStateException()
1033 } else if (o == 7) {
1034 tar(n([s, 2, x, 1, y]), {
1037 } else if (o == 8) {
1038 tar(n([s, 7, [[7, [0, 1], x], 0, 1], y]), {
1041 } else if (o == 9) {
1042 tar(n([s, 7, y, 2, [0, 1], 0, x]), {
1045 } else if (o == 10) {
1051 tar(n([s, 8, x[1], 7, [0, 3], y]), {
1057 throw new IllegalStateException()
1060 tar(n([s, 2, [0, 1], 2, [1, y[0], y[1]], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, x]), {
1064 throw new IllegalStateException()
1074From [Steve Dee](https://github.com/mrdomino/hsnock/blob/master/Language/Nock5K/Spec.hs):
1077module Language.Nock5K.Spec where
1078import Control.Monad.Instances
1080wut (a :- b) = return $ Atom 0
1081wut a = return $ Atom 1
1083lus (a :- b) = Left "+[a b]"
1084lus (Atom a) = return $ Atom (1 + a)
1086tis (a :- a') | a == a' = return $ Atom 0
1087tis (a :- b) = return $ Atom 1
1090fas (Atom 1 :- a) = return a
1091fas (Atom 2 :- a :- b) = return a
1092fas (Atom 3 :- a :- b) = return b
1093fas (Atom a :- b) | a > 3 = do x <- fas $ Atom (a `div` 2) :- b
1094 fas $ Atom (2 + (a `mod` 2)) :- x
1097tar (a :- (b :- c) :- d) = do x <- tar (a :- b :- c)
1101tar (a :- Atom 0 :- b) = fas $ b :- a
1102tar (a :- Atom 1 :- b) = return b
1103tar (a :- Atom 2 :- b :- c) = do x <- tar (a :- b)
1106tar (a :- Atom 3 :- b) = tar (a :- b) >>= wut
1107tar (a :- Atom 4 :- b) = tar (a :- b) >>= lus
1108tar (a :- Atom 5 :- b) = tar (a :- b) >>= tis
1110tar (a :- Atom 6 :- b :- c :- d) = tar (a :- Atom 2 :- (Atom 0 :- Atom 1) :-
1111 Atom 2 :- (Atom 1 :- c :- d) :-
1112 (Atom 1 :- Atom 0) :- Atom 2 :-
1113 (Atom 1 :- Atom 2 :- Atom 3) :-
1114 (Atom 1 :- Atom 0) :- Atom 4 :-
1116tar (a :- Atom 7 :- b :- c) = tar (a :- Atom 2 :- b :- Atom 1 :- c)
1117tar (a :- Atom 8 :- b :- c) = tar (a :- Atom 7 :-
1118 ((Atom 7 :- (Atom 0 :- Atom 1) :- b) :-
1119 Atom 0 :- Atom 1) :- c)
1120tar (a :- Atom 9 :- b :- c) = tar (a :- Atom 7 :- c :- Atom 2 :-
1121 (Atom 0 :- Atom 1) :- Atom 0 :- b)
1122tar (a :- Atom 10 :- (b :- c) :- d) = tar (a :- Atom 8 :- c :- Atom 7 :-
1123 (Atom 0 :- Atom 3) :- d)
1124tar (a :- Atom 10 :- b :- c) = tar (a :- c)
1136 [$(fol -.fol) $(fol +.fol)]
1143 =+ [now=(cap b.fol) lat=(mas b.fol)]
1144 $(b.fol lat, sub ?:(=(2 now) -.sub +.sub))
1151 $(sub -.ben, fol +.ben)
1168 $(fol =>(fol [2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]))
1170 {$7 b/* c/*} $(fol =>(fol [2 b 1 c]))
1171 {$8 b/* c/*} $(fol =>(fol [7 [[7 [0 1] b] 0 1] c]))
1172 {$9 b/* c/*} $(fol =>(fol [7 c 2 [0 1] 0 b]))
1173 {$10 @ c/*} $(fol c.fol)
1174 {$10 {b/* c/*} d/*} =+($(fol c.fol) $(fol d.fol))
1180From [Joe Bryan](https://github.com/joemfb/nock.js/blob/master/nock.js):
1183(function (self, factory) {
1186 if (typeof define === 'function' && define.amd) {
1188 } else if (typeof module === 'object' && typeof module.exports === 'object') {
1189 module.exports = factory()
1191 self.nock = factory()
1193}(this, function () {
1197 * Nock is a combinator interpreter on nouns. A noun is an atom or a cell.
1198 * An atom is an unsigned integer of any size; a cell is an ordered pair of nouns.
1200 * @see http://urbit.org/docs/nock/definition/
1201 * @see https://media.urbit.org/whitepaper.pdf
1204 var useMacros = false
1210 * `s` is a subject noun,
1211 * `f` is a formula (or cell of formulas)
1217 * wut (?): test for atom (1) or cell (0)
1223 return typeof n === 'number' ? 1 : 0
1227 * lus (+): increment an atom
1233 if (wut(n) === 0) throw new Error('lus cell')
1238 * tis (=): test equality
1245 if (wut(n) === 1) throw new Error('tis atom')
1246 return deepEqual(n[0], n[1]) ? 0 : 1
1250 * fas (/): resolve a tree address
1255 * /[(a + a) b] /[2 /[a b]]
1256 * /[(a + a + 1) b] /[3 /[a b]]
1259 function fas (addr, n) {
1260 if (n === undefined) throw new Error('invalid fas noun')
1261 if (addr === 0) throw new Error('invalid fas addr: 0')
1263 if (addr === 1) return n
1264 if (addr === 2) return n[0]
1265 if (addr === 3) return n[1]
1267 return fas(2 + (addr % 2), fas((addr / 2) | 0, n))
1273 * slot (0): resolve a tree address
1277 function slot (s, f) {
1280 if (p === undefined) throw new Error('invalid fas addr: ' + f)
1286 * constant (1): return the formula regardless of subject
1290 function constant (s, f) {
1295 * evaluate (2): evaluate the product of second formula against the product of the first
1297 * *[a 2 b c] *[*[a b] *[a c]]
1299 function evaluate (s, f) {
1300 return nock(nock(s, f[0]), nock(s, f[1]))
1304 * cell (3): test if the product is a cell
1308 function cell (s, f) {
1309 return wut(nock(s, f))
1313 * incr (4): increment the product
1317 function incr (s, f) {
1318 return lus(nock(s, f))
1322 * eq (5): test for equality between nouns in the product
1326 function eq (s, f) {
1327 return tis(nock(s, f))
1330 /* macro-formulas */
1333 * ife (6): if/then/else
1335 * *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1337 function macroIfe (s, f) {
1338 return nock(s, [2, [[0, 1], [2, [[1, [f[1][0], f[1][1]]], [[1, 0], [2, [[1, [2, 3]], [[1, 0], [4, [4, f[0]]]]]]]]]]])
1341 function ife (s, f) {
1342 var cond = nock(s, f[0])
1344 if (cond === 0) return nock(s, f[1][0])
1345 if (cond === 1) return nock(s, f[1][1])
1347 throw new Error('invalid ife conditional')
1351 * compose (7): evaluate formulas composed left-to-right
1353 * *[a 7 b c] *[a 2 b 1 c]
1355 function macroCompose (s, f) {
1356 return nock(s, [2, [f[0], [1, f[1]]]])
1359 function compose (s, f) {
1361 // return nock(nock(s, f[0]), constant(s, f[1]))
1362 return nock(nock(s, f[0]), f[1])
1366 * extend (8): evaluate the second formula against [product of first, subject]
1368 * *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
1370 function macroExtend (s, f) {
1371 return nock(s, [7, [[[7, [[0, 1], f[0]]], [0, 1]], f[1]]])
1374 function extend (s, f) {
1376 // return nock([compose(s, [[0, 1], f[0]]), s], f[1])
1377 return nock([nock(s, f[0]), s], f[1])
1381 * invoke (9): construct a core and evaluate one of it's arms against it
1383 * *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
1385 function macroInvoke (s, f) {
1386 return nock(s, [7, [f[1], [2, [[0, 1], [0, f[0]]]]]])
1389 function invoke (s, f) {
1390 var prod = nock(s, f[1])
1391 return nock(prod, slot(prod, f[0]))
1395 * hint (10): skip first formula, evaluate second
1397 * *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
1398 * *[a 10 b c] *[a c]
1400 function macroHint (s, f) {
1401 if (wut(f[0]) === 0) return nock(s, [8, [f[0][1], [7, [[0, 3], f[1]]]]])
1402 return nock(s, f[1])
1405 function hint (s, f) {
1406 if (wut(f[0]) === 0) {
1407 if (wut(f[0][1]) === 1) throw new Error('invalid hint')
1410 return nock(s, f[1])
1413 /* indexed formula functions */
1414 var macroFormulas = [slot, constant, evaluate, cell, incr, eq, macroIfe, macroCompose, macroExtend, macroInvoke, macroHint]
1415 var formulas = [slot, constant, evaluate, cell, incr, eq, ife, compose, extend, invoke, hint]
1422 * *[a [b c] d] [*[a b c] *[a d]]
1425 function nock (s, f) {
1426 if (wut(f[0]) === 0) return [nock(s, f[0]), nock(s, f[1])]
1430 if (idx > 10) throw new Error('invalid formula: ' + idx)
1432 if (useMacros) return macroFormulas[idx](s, f[1])
1434 return formulas[idx](s, f[1])
1437 /* construct a JS noun (group an array into pairs, associating right) */
1438 function assoc (x) {
1439 if (!x.length) return x
1441 if (x.length === 1) return assoc(x[0])
1443 return [assoc(x[0]), assoc(x.slice(1))]
1446 /* deep equality for arrays or primitives */
1447 function deepEqual (a, b) {
1448 if (a === b) return true
1450 if (!(Array.isArray(a) && Array.isArray(b))) return false
1451 if (a.length !== b.length) return false
1453 for (var i = 0; i < a.length; i++) {
1454 if (!deepEqual(a[i], b[i])) return false
1460 /* parse a hoon-serialized nock formula and construct a JS noun */
1461 function parseNoun (x) {
1462 if (Array.isArray(x)) return assoc(x)
1464 if (typeof x === 'string') {
1465 var str = x.replace(/[\."']/g, '').split(' ').join(',')
1466 return assoc(JSON.parse(str))
1472 function nockInterface () {
1473 var args = [].slice.call(arguments)
1474 var subject, formula, noun
1476 if (args.length === 1) {
1477 formula = parseNoun(args[0])
1478 } else if (args.length === 2) {
1479 subject = parseNoun(args[0])
1480 formula = parseNoun(args[1])
1487 if (!formula) throw new Error('formula required')
1494 return nock(subject, formula)
1498 nock: nockInterface,
1500 useMacros: function (arg) {
1501 useMacros = arg === undefined || arg
1506 parseNoun: parseNoun,
1507 deepEqual: deepEqual
1524 macroCompose: macroCompose,
1526 macroExtend: macroExtend,
1528 macroInvoke: macroInvoke,
1530 macroHint: macroHint,
1539From [James Tauber](https://github.com/jtauber/pynock/blob/master/nock.py):
1542#!/usr/bin/env python3
1551 return (lst[0], l(*lst[1:]))
1559 if isinstance(noun, int):
1567 if isinstance(noun, int):
1575 if noun[0] == noun[1]:
1589 elif noun[0] % 2 == 0:
1590 return slot((2, slot((noun[0] // 2, noun[1]))))
1591 elif noun[0] % 2 == 1:
1592 return slot((3, slot(((noun[0] - 1) // 2, noun[1]))))
1596 if isinstance(noun[1][0], int):
1598 return slot((noun[1][1], noun[0]))
1599 elif noun[1][0] == 1:
1601 elif noun[1][0] == 2:
1602 return nock((nock((noun[0], noun[1][1][0])), nock((noun[0], noun[1][1][1]))))
1603 elif noun[1][0] == 3:
1604 return wut(nock((noun[0], noun[1][1])))
1605 elif noun[1][0] == 4:
1606 return lus(nock((noun[0], noun[1][1])))
1607 elif noun[1][0] == 5:
1608 return tis(nock((noun[0], noun[1][1])))
1609 elif noun[1][0] == 6:
1610 return nock(l(noun[0], 2, (0, 1), 2, l(1, noun[1][1][1][0], noun[1][1][1][1]), (1, 0), 2, l(1, 2, 3), (1, 0), 4, 4, noun[1][1][0]))
1611 elif noun[1][0] == 7:
1612 return nock(l(noun[0], 2, noun[1][1][0], 1, noun[1][1][1]))
1613 elif noun[1][0] == 8:
1614 return nock(l(noun[0], 7, l(l(7, (0, 1), noun[1][1][0]), 0, 1), noun[1][1][1]))
1615 elif noun[1][0] == 9:
1616 return nock(l(noun[0], 7, noun[1][1][1], l(2, (0, 1), (0, noun[1][1][0]))))
1617 elif noun[1][0] == 10:
1618 if isinstance(noun[1][1][0], int):
1619 return nock((noun[0], noun[1][1][1]))
1621 return nock(l(noun[0], 8, noun[1][1][0][1], 7, (0, 3), noun[1][1][1][0]))
1623 return (nock((noun[0], noun[1][0])), nock((noun[0], noun[1][1])))
1628From [T.J. Corcoran](https://github.com/TJamesCorcoran/nock/blob/master/nock.rb):
1633 str.scan(/\+|\=|\?|\/|\*|\[|\]|\d+/).each do |token|
1638 ret = arr.is_a?(Array) ? [max_depth(arr[0]), max_depth(arr[1])].max + 1 : 1
1643 depth = max_depth(arr)
1645 1.up_to(8) do |depth|
1647 min = 2 ** (depth - 1)
1648 max = (2 ** depth) - 1
1649 min.upto(max) { |axis|
1655 return arr unless arr.is_a?(Array)
1658 arr[size - 2] = [ arr[size - 2], arr.pop ]
1660 arr = arr.map { |x| norm(x) }
1664 arr.is_a?(Array) ? YES : NO
1668 raise "not an atom" unless atom.is_a?(Fixnum)
1673 raise "not pair" unless arr.is_a?(Array) && arr.size == 2
1674 ( arr[0] == arr[1] ) ? YES : NO
1677def slot(axis, arr, allow_error = true)
1678 raise "axis on atom" unless arr.is_a?(Array)
1679 return arr if axis == 1
1680 return arr[0] if axis == 2
1681 return arr[1] if axis == 3
1682 return slot(2, slot(axis/2, arr)) if (axis %2) == 0
1683 return slot(3, slot(axis/2, arr))
1688 raise "error: nocking an atom" unless arr.is_a?(Array)
1694 if oper.is_a?(Array)
1695 return [ nock( [ a, [b, c]]), nock( [a, d]) ]
1707 b_prime = slot(2, b)
1709 nock( [ nock([a, b_primce]), nock([a, c]) ])
1721 b_prime = slot(2, b)
1724 nock( norm([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b]) )
1727 b_prime = slot(2, b)
1729 nock( norm ([a, 2, b_prime, 1, c]))
1732 b_prime = slot(2, b)
1734 nock( norm ([a, 7, [[7, [0, 1], b_prime], 0, 1], c]))
1737 b_prime = slot(2, b)
1739 nock( norm ([a, 7, c, 2, [0, 1], 0, b_prime]))
1742 if wut(slot(2,b)) == TRUE
1743 b_prime = slot(4, b)
1747 nock( norm ([a, 8, c, 7, [0, 3], d]))
1749 b_prime = slot(2, b)
1751 nock( norm ([a, 10, [b, c]]))
1754 raise "error: unknown opcode #{oper.inspect}"
1761From [Steve Randy Waldman](https://github.com/swaldman/nnnock/blob/master/src/main/scala/com/mchange/sc/v1/nnnock/package.scala):
1764package object nnnock {
1767 case class Atom( value : Int ) extends Noun;
1768 case class Cell( head : Noun, tail : Noun ) extends Noun;
1769 implicit def toAtom( value : Int ) : Atom = Atom( value );
1770 implicit def toInt( atom : Atom ) : Int = atom.value;
1772 def nock( a : Noun ) : Noun = *(a)
1776 private def apply( nl : List[Noun] ) : Cell = {
1778 case a :: b :: Nil => Cell(a, b);
1779 case a :: b :: c :: Nil => Cell(a, Cell(b, c));
1780 case a :: b :: c :: tail => Cell(a, this.apply( b :: c :: tail ) );
1783 def apply(a : Noun, b : Noun, tail : Noun*) : Cell = apply( a :: b :: tail.toList );
1786 def ?( noun : Noun ) : Noun = noun match {
1791 @tailrec def plus( noun : Noun ) : Noun = noun match {
1792 case a : Atom => 1 + a;
1793 case c : Cell => plus( c ); //intentional endless spin
1796 def heq( noun : Noun ) : Atom = noun match {
1797 case Cell( a : Atom, b : Atom ) => if ( a == b ) 0 else 1;
1798 case Cell( a : Cell, b : Atom ) => 1;
1799 case Cell( a : Atom, b : Cell ) => 1;
1800 case Cell( a : Cell, b : Cell ) => if ((heq( Cell( a.head, b.head ) ) | heq( Cell( a.tail, b.tail ) )) == 0) 0 else 1;
1801 case a : Atom => heq( a ); //intentional endless spin
1804 def /( noun : Noun ) : Noun = noun match {
1805 case Cell(Atom(1), a) => a;
1806 case Cell(Atom(2), Cell(a, b)) => a;
1807 case Cell(Atom(3), Cell(a, b)) => b;
1808 case Cell(Atom(value), b ) => {
1810 val num = if ( value % a == 0 ) 2 else 3;
1811 /(Cell(num, /(Cell(a, b))));
1813 case a => /( a ); //intentional endless spin
1817 def *( noun : Noun ) : Noun = noun match {
1818 case Cell( a, Cell(Cell(b, c), d) ) => Cell( *(Cell(a,b,c)), *(Cell(a,d)) );
1819 case Cell( a, Cell(Atom(value), tail) ) => {
1820 (value, tail) match {
1821 case (0, b) => /( Cell(b, a) );
1823 case (2, Cell(b, c)) => *( Cell( *( Cell(a,b) ), *( Cell(a,c) ) ) );
1824 case (3, b) => ?( *( Cell(a,b) ) );
1825 case (4, b) => plus( *( Cell(a,b) ) );
1826 case (5, b) => heq( *( Cell(a,b) ) );
1827 case (6, Cell(b, Cell(c, d))) => *( Cell(a,2,Cell(0,1),2,Cell(1,c,d),Cell(1,0),2,Cell(1,2,3),Cell(1,0),4,4,b) ); //wtf?
1828 case (7, Cell(b, c)) => *( Cell(a,2,b,1,c) );
1829 case (8, Cell(b, c)) => *( Cell(a,7,Cell(Cell(7,Cell(0,1),b),0,1),c) ); //wtf2
1830 case (9, Cell(b, c)) => *( Cell(a,7,c,2,Cell(0,1),0,b) );
1831 case (10, Cell(Cell(b,c),d)) => *( Cell(a,8,c,7,Cell(0,3),d) );
1832 case (10, Cell(b, c)) => *( Cell(a,c) );
1833 case _ => *( noun ); //intentional endless spin
1836 case a => *( a ); //intentional endless spin
1843From [Kohányi Róbert](https://github.com/kohanyirobert/snock/blob/master/snock.ss):
1853 (let ((l (length a)))
1855 ((equal? l 0) (raise 1))
1856 ((equal? l 1) (r (car a)))
1859 ((equal? l 2) (cadr a))
1863 (lambda (q) (r (cons p q)))))))))))
1874 ((equal? (wut a) 0) (raise 3))
1879 ((equal? (wut a) 1) (raise 4))
1880 ((equal? (car a) (cdr a)) 0)
1885 ((equal? (wut a) 1) (raise 5))
1890 ((not (fixnum? h)) (raise 6))
1891 ((equal? h 0) (raise 7))
1892 ((equal? h 1) (r t))
1893 ((fixnum? t) (raise 8))
1894 ((equal? h 2) (r (car t)))
1895 ((equal? h 3) (r (cdr t)))
1897 (fas (cons (div h 2) t)
1898 (lambda (p) (fas (cons (+ 2 (mod h 2)) p)
1899 (lambda (q) (r q)))))))))))
1903 ((equal? (wut a) 1) (raise 9))
1908 ((equal? (wut f) 1) (raise 10))
1913 ((equal? (wut o) 0) (tar (cons s o)
1914 (lambda (p) (tar (cons s v)
1915 (lambda (q) (r (cons p q)))))))
1916 ((equal? o 0) (r (fas (cons v s) i)))
1917 ((equal? o 1) (r v))
1918 ((equal? o 3) (tar (cons s v)
1919 (lambda (p) (r (wut p)))))
1920 ((equal? o 4) (tar (cons s v)
1921 (lambda (p) (r (lus p)))))
1922 ((equal? o 5) (tar (cons s v)
1923 (lambda (p) (r (tis p)))))
1924 ((equal? (wut v) 1) (raise 11))
1929 ((equal? o 2) (tar (cons s x)
1930 (lambda (p) (tar (cons s y)
1931 (lambda (q) (tar (cons p q)
1932 (lambda (u) (r u))))))))
1933 ((equal? o 7) (tar (n (list (list s) 2 (list x) 1 (list y)) i)
1934 (lambda (p) (r p))))
1935 ((equal? o 8) (tar (n (list (list s) 7 (list (list 7 (list 0 1) (list x)) 0 1) (list y)) i)
1936 (lambda (p) (r p))))
1937 ((equal? o 9) (tar (n (list (list s) 7 (list y) 2 (list 0 1) 0 (list x)) i)
1938 (lambda (p) (r p))))
1939 ((equal? o 10) (cond
1940 ((equal? (wut x) 1) (tar (cons s y)
1941 (lambda (p) (r p))))
1942 (else (tar (n (list (list s) 8 (list (cdr x)) 7 (list 0 3) (list y)) i)
1943 (lambda (p) (r p))))))
1944 ((equal? (wut y) 1) (raise 12))
1945 ((equal? o 6) (tar (n (list
1950 (list 1 (list (car y)) (list (cdr y)))
1959 (lambda (p) (r p))))
1960 (else (raise 13)))))))))))))
1967// 1 :: A noun is an atom or a cell.
1968// 2 :: An atom is a natural number.
1969// 3 :: A cell is an ordered pair of nouns.
1972// 6 :: [a b c] [a [b c]]
1976// 10 :: +[a b] +[a b]
1985// 19 :: /[(a + a) b] /[2 /[a b]]
1986// 20 :: /[(a + a + 1) b] /[3 /[a b]]
1989// 23 :: *[a [b c] d] [*[a b c] *[a d]]
1991// 25 :: *[a 0 b] /[b a]
1993// 27 :: *[a 2 b c] *[*[a b] *[a c]]
1994// 28 :: *[a 3 b] ?*[a b]
1995// 29 :: *[a 4 b] +*[a b]
1996// 30 :: *[a 5 b] =*[a b]
1998// 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
1999// 33 :: *[a 7 b c] *[a 2 b 1 c]
2000// 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2001// 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2002// 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2003// 37 :: *[a 10 b c] *[a c]
2007// 1 :: A noun is an atom or a cell.
2008public indirect enum Noun: IntegerLiteralConvertible, ArrayLiteralConvertible, Equatable, Hashable, CustomStringConvertible
2010 // 2 :: An atom is a natural number.
2011 public typealias ATOM = UIntMax
2014 // 3 :: A cell is an ordered pair of nouns.
2015 case Cell(Noun, Noun)
2018 public static var YES: Noun { return .Atom(0) }
2019 public static var NO: Noun { return .Atom(1) }
2021 public init(_ noun: Noun) { self = noun }
2023 // 6 :: [a b c] [a [b c]]
2024 public init(_ nouns: [Noun]) {
2026 if nouns.count > 0 {
2027 var reverse = nouns.reverse().generate()
2028 self = reverse.next()!
2029 while let n = reverse.next() {
2030 self = .Cell(n, self)
2035 // protocol IntegerLiteralConvertible
2036 public typealias IntegerLiteralType = ATOM
2037 public init(integerLiteral value: IntegerLiteralType) {
2041 // protocol ArrayLiteralConvertible
2042 public typealias Element = Noun
2043 public init(arrayLiteral elements: Element...) {
2044 self = Noun(elements)
2048 public subscript(axis: ATOM) -> Noun {
2049 return fas(.Cell(.Atom(axis), self))
2052 // protocol Hashable
2053 public var hashValue: Int {
2054 //return self.description.hashValue
2058 case let .Cell(a, b):
2059 return (5381 + 31 &* a.hashValue) &+ b.hashValue
2065 // protocol CustomStringConvertible
2066 public var description: String {
2070 private func describe(depth: Int = 0) -> String {
2075 return "[%INVALID%]"
2076 case let .Atom(atom):
2078 case let .Cell(.Cell(a, b), c):
2079 sub = "[\(a.describe(next)) \(b.describe(next))] \(c.describe(next))"
2080 case let .Cell(a, b):
2081 sub = "\(a.describe(next)) \(b.describe(next))"
2083 return depth == 0 ? "[\(sub)]" : sub
2087// protocol Equatable
2088public func == (left: Noun, right: Noun) -> Bool
2090 switch (left, right) {
2091 case let (.Atom(lhs), .Atom(rhs)): return lhs == rhs
2092 case let (.Cell(lp, lq), .Cell(rp, rq)): return lp == rp && lq == rq
2093 case (.Invalid, .Invalid): return true
2094 default: return false
2098public func wut(noun: Noun) -> Noun
2113public func lus(noun: Noun) -> Noun
2115 if case let .Atom(a) = noun {
2119 // 10 :: +[a b] +[a b]
2124public func tis(noun: Noun) -> Noun
2126 if case let .Cell(a, b) = noun {
2129 return (a == b) ? Noun.YES : Noun.NO
2136public func fas(noun: Noun) -> Noun
2140 case let .Cell(1, a):
2143 case let .Cell(2, .Cell(a, _)):
2146 case let .Cell(3, .Cell(_, b)):
2148 // 19 :: /[(a + a) b] /[2 /[a b]]
2149 // 20 :: /[(a + a + 1) b] /[3 /[a b]]
2150 case let .Cell(.Atom(axis), tree):
2151 let inner = Noun.Atom(axis / 2)
2152 let outer = Noun.Atom(2 + (axis % 2))
2153 return fas(.Cell(outer, fas(.Cell(inner, tree))))
2161public func tar(noun: Noun) -> Noun
2164 case let .Cell(a, formula):
2166 // 23 :: *[a [b c] d] [*[a b c] *[a d]]
2167 case let .Cell(.Cell(b, c), d):
2168 return .Cell(tar([a, b, c]), tar([a, d]))
2170 // 25 :: *[a 0 b] /[b a]
2171 case let .Cell(0, b):
2175 case let .Cell(1, b):
2178 // 27 :: *[a 2 b c] *[*[a b] *[a c]]
2179 case let .Cell(2, .Cell(b, c)):
2180 return tar([tar([a, b]), tar([a, c])])
2182 // 28 :: *[a 3 b] ?*[a b]
2183 case let .Cell(3, b):
2184 return wut(tar([a, b]))
2186 // 29 :: *[a 4 b] +*[a b]
2187 case let .Cell(4, b):
2188 return lus(tar([a, b]))
2190 // 30 :: *[a 5 b] =*[a b]
2191 case let .Cell(5, b):
2192 return tis(tar([a, b]))
2194 // 32 :: *[a 6 b c d] *[a 2 [0 1] 2 [1 c d] [1 0] 2 [1 2 3] [1 0] 4 4 b]
2195 case let .Cell(6, .Cell(b, .Cell(c, d))):
2196 return tar([a, 2, [0, 1], 2, [1, c, d], [1, 0], 2, [1, 2, 3], [1, 0], 4, 4, b])
2198 // 33 :: *[a 7 b c] *[a 2 b 1 c]
2199 case let .Cell(7, .Cell(b, c)):
2200 return tar([a, 2, b, 1, c])
2202 // 34 :: *[a 8 b c] *[a 7 [[7 [0 1] b] 0 1] c]
2203 case let .Cell(8, .Cell(b, c)):
2204 return tar([a, 7, [[7, [0, 1], b], 0, 1], c])
2206 // 35 :: *[a 9 b c] *[a 7 c 2 [0 1] 0 b]
2207 case let .Cell(9, .Cell(b, c)):
2208 return tar([a, 7, c, 2, [0, 1], 0, b])
2210 // 36 :: *[a 10 [b c] d] *[a 8 c 7 [0 3] d]
2211 case let .Cell(10, .Cell(.Cell(_, c), d)):
2212 return tar([a, 8, c, 7, [0, 3], d])
2214 // 37 :: *[a 10 b c] *[a c]
2215 case let .Cell(10, .Cell(_, c)):
2229public var nock_functions = Dictionary<Noun, Noun -> Noun>()
2231public func dao(formula: Noun) -> Noun->Noun
2233 if let cached = nock_functions[formula] {
2237 let compiler = { () -> Noun -> Noun in
2239 case let .Cell(.Cell(b, c), d): // Distribution
2240 let (p, q) = (dao(.Cell(b, c)), dao(d))
2241 return { a in .Cell(p(a), q(a)) }
2243 case let .Cell(0, b): // Axis
2244 return { a in fas(.Cell(b, a)) }
2246 case let .Cell(1, b): // Just
2249 case let .Cell(2, .Cell(b, c)): // Fire
2250 let (f, g) = (dao(b), dao(c))
2251 return { a in dao(g(a))(f(a)) }
2253 case let .Cell(3, b): // Depth
2255 return { a in wut(f(a)) }
2257 case let .Cell(4, b): // Bump
2259 return { a in lus(f(a)) }
2261 case let .Cell(5, b): // Same
2263 return { a in tis(f(a)) }
2265 case let .Cell(6, .Cell(b, .Cell(c, d))): // If
2266 let (p, q, r) = (dao(b), dao(c), dao(d))
2274 return tar(.Cell(a, formula))
2278 case let .Cell(7, .Cell(b, c)): // Compose
2279 let (f, g) = (dao(b), dao(c))
2280 return { a in g(f(a)) }
2282 case let .Cell(8, .Cell(b, c)): // Push
2283 let (f, g) = (dao(b), dao(c))
2284 return { a in g(.Cell(f(a), a)) }
2286 case let .Cell(9, .Cell(b, c)): // Call
2290 let arm = dao(fas(.Cell(b, core)))
2294 case let .Cell(10, .Cell(.Cell(_, c), d)): // Hint
2297 return { a in ignore(a); return f(a) }
2299 case let .Cell(10, .Cell(_, c)): // Hint
2301 return { a in f(a) }
2304 return { a in tar(.Cell(a, formula)) }
2309 nock_functions[formula] = r
2313public func nock(n: Noun) -> Noun
2315 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