By using LoF to represent values all operations are effectively binary digital circuits. So this is a way to model hardware by orchestrating it with Joy code. For example, an 8-bit integer zero could be represented as [[][][][][][][][]] and so on: [ [] [] [] [] [] [] [] [] ] 0 [ [] [] [] [] [] [] [] [[]]] 1 [ [] [] [] [] [] [] [[]] [] ] 2 [ [] [] [] [] [] [] [[]][[]]] 3 Treating [] as zero and [[]] as one. Sum = a xor b xor c Carry = (b and a) or (c and (b xor a)) Sum = a ⊕ b ⊕ c Carry = (b ∧ a) ∨ (c ∧ (b ⊕ a)) ∧∨⊕ def full_bit_adder(a, b, c): '''Based on the definitions from Wikipedia.''' return ( simplify(xor(xor(a, b), c)), simplify(or_(and_(a, b), and_(c, xor(a, b)))), ) c b a [xor xor void] [[and] [xor and] fork or void] clop popdd c b a [and] [xor and] clop c (b and a) (c and (b xor a)) or c ((b and a) or (c and (b xor a))) fba == [xor xor void] [[and] [xor and] fork or void] clop popdd So we have a full-bit adder (with carry in and out), it's a trinary function with binary output. carry b a fba ------------------- carry' (a+b) Now we need a function that takes two 8-bit "numbers" and a carry bit and returns a single 8-bit number with the carry bit out. carry [.b.] [.a.] + ------------------------- carry' [a+b] The first thing that comes to my mind as a "2step" combinator: [b ...] [a ...] [F] 2step --------------------------------- b a F [,,,] [,,,] [F] 2step And so on; if lists aren't the same length...? Could just zip the tho lists and use step. Then merge zip and the step form? I think you would still want to define zip in terms of 2step. zipF == <<{} [unswons] dip uncons [duo swap [cons] dip] dip How's that work: [b ...] [a ...] <<{} [unswons] dip uncons [duo swap [cons] dip] dip [] [b ...] [a ...] [unswons] dip uncons [duo swap [cons] dip] dip [] [b ...] unswons [a ...] uncons [duo swap [cons] dip] dip [] [...] b [a ...] uncons [duo swap [cons] dip] dip [] [...] b a [...] [duo swap [cons] dip] dip [] [...] b a duo swap [cons] dip [...] [] [...] [b a] swap [cons] dip [...] [] [b a] [...] [cons] dip [...] Opps! swons! [] [b a] [...] [swons] dip [...] [] [b a] swons [...] [...] [[b a]] [...] [...] [[b a]] [...] [...] The other bug in this is that you wind up with the pairs in the new list in reverse order from the original lists. Time to review recursion combinators... Or, just collect the bits at the end? c8b == [] [[[[[[[[[]]]]]]]]] [cons] times To deal with the Carry bit let it ride at TOS then grab the bits under it and swap to get the result byte above the carry bit. fin == [c8b] dip swap Or rewrite fba to have carry on tos? c [b ...] [a ...] [uncons] dip unswons rolldown c [b ...] uncons [a ...] unswons rolldown c b [...] [a ...] unswons rolldown c b [...] [...] a rolldown c b a [...] [...] Okay, then: c b a [...] [...] [fba swap] dipd c b a fba swap [...] [...] c' a+b swap [...] [...] a+b c' [...] [...] So (using ints as shorthand for Peano numbers): F == [uncons] dip unswons rolldown [fba swap] dipd c8b == [] 8 [cons] times + == 8 [F] times popop [c8b] dip swap Note the function that uncons's a pair from two lists compiles to a primitive nicely: ?- sjc(uncons-pair, `[uncons] dip unswons rolldown`). func(uncons-pair, [list([C|A]), list([D|B])|E], [list(A), list(B), C, D|E]). uncons-pair == [uncons] dip unswons rolldown F == uncons-pair [fba swap] dipd c8b == [] 8 [cons] times + == 8 [F] times popop [c8b] dip swap Also c8b: ?- sjc(foo, `[] 8 [cons] times`). func(foo, [H, G, F, E, D, C, B, A|I], [list([A, B, C, D, E, F, G, H])|I]). sjc(foo, `[[] 8 [cons] times] dip swap`). func(foo, [int(I), H, G, F, E, D, C, B, A|J], [list([A, B, C, D, E, F, G, H]), int(I)|J]). Hmm... (I'm using main thun, it hallucinates literals...) Easy enough to fix manually... func(foo, [I, H, G, F, E, D, C, B, A|J], [list([A, B, C, D, E, F, G, H]), I|J]). But it would be nice to figure out exactly why it can't hallucinate the most general case (first) and make it do that. - - - - THe other thing to do would be to build up the formulas with (atoms) vars for the input signals and then use LoF simplification to precompute formulas for each output bit (including carry) and the write one function that directly builds the output byte and carry from the input byte and carry by direct unification in Prolog and then run `cons [void] map uncons` on it to reduce the formulas. - - - - Sum = a xor b xor c Carry = (b and a) or (c and (b xor a)) Sum = a ⊕ b ⊕ c Carry = (b ∧ a) ∨ (c ∧ (b ⊕ a)) ∧∨⊕¬∥¿ c b a [⊕ ⊕ ¿] [[∧] [⊕ ∧] ∥ ∨ ¿] ∥ppp ∥ = [i] app2 ∥p == ∥ popdd ∥pp == ∥p popdd ∥ppp == ∥pp popdd cleave == fork popdd clop == cleave popdd clopp == clop popdd [⊕ ⊕ ¿] [[∧] [⊕ ∧] ∥ ∨ ¿] ∥ppp - - - - list\(([^)]+)\) or == [unit] ii unit cons and == unit cons unit not == unit or == [not] ii not cons and == not cons not xor == [unit unit cons] [swap unit unit cons] cleave unit cons ------------------------------ Messing about with binary Boolean semantics and the Joy programming language, implementing a full-bit adder. https://en.wikipedia.org/wiki/Adder_(electronics)#Full_adder > A full adder adds binary numbers and accounts for values carried in as well as out. A one-bit full-adder adds three one-bit numbers, often written as A, B, and Cin; A and B are the operands, and Cin is a bit carried in from the previous less-significant stage. As logical expression with operators: sum = a xor b xor c carry = (b and a) or (c and (b xor a)) Replace the words with common symbols (APL envy?) sum = a ⊕ b ⊕ c carry = (b ∧ a) ∨ (c ∧ (b ⊕ a)) As Python psuedo-code: def full_bit_adder(a, b, c): return ( simplify(xor(xor(a, b), c)), simplify(or_(and_(a, b), and_(c, xor(a, b)))), ) As Joy: [xor xor simplify] [[and] [xor and] fork or simplify] clop popdd With cute symbols: [⊕ ⊕ ¿] [[∧] [⊕ ∧] ∥ ∨ ¿] ∥ppp Factoring out the simplify function (represented by '¿'): [⊕ ⊕] [[∧] [⊕ ∧] ∥ ∨] ∥ppp [¿] ii One thing to note, the parentheses in the equational and Python forms are encoding operator precedence while the square brackets in the Joy expression encode the control-flow-independence of the sub-functions of the main function, they *quote* the sub-subfunctions so they can be arguments to the '∥' and '∥ppp' concurrency combinators. - - - - "Selfie" as an alternate target to Oberon. https://selfie.cs.uni-salzburg.at/ https://news.ycombinator.com/item?id=22427189 https://github.com/cksystemsteaching/selfie/blob/master/semantics.md - - - - https://www.geoffreylitt.com/wildcard/salon2020/ Wildcard: Spreadsheet-Driven Customization of Web Applications By Geoffrey Litt and Daniel Jackson https://edtr.io/ https://news.ycombinator.com/item?id=22451568 https://handsontable.com/ JavaScript data grid that looks and feels like a spreadsheet. https://www.tampermonkey.net/ Tampermonkey is a userscript manager https://www.cs.kent.ac.uk/people/staff/dat/miranda/ https://en.wikipedia.org/wiki/Miranda_(programming_language) https://news.ycombinator.com/item?id=22447185 https://ncatlab.org/nlab/show/differentiation file:///C:/Users/sforman/Desktop/FooNolder/1803.10228.pdf Demystifying Differentiable Programming:Shift/Reset the Penultimate Backpropagator https://news.ycombinator.com/item?id=22343285 Domain Modelling made Functional https://www.youtube.com/watch?v=Up7LcbGZFuo https://langserver.org/ https://news.ycombinator.com/item?id=22442133