I was confused about what <4> = \lambda ^ 5 4 meant, since it already seemed to have a "4" in it.
The trick is that the 4 seems to be similar to a positional argument index, but numbered inside out.
IOW, in this encoding, <4> is a function that can be called 5 times (the exponent on the lambda) and upon the fifth call will resolve to whatever was passed in 1st (which because of the inside-out ordering is labeled "4").
(For a simpler example, 0 is a function that can be called once and returns its argument.)
So succ is 3-ary; it says, give me a function (index 2, outermost call); next, give me its first argument (index 1, second-outermost call); when you call that (index 0, dropped, innermost call), I'll apply the function to the argument.
But note that if index 2 is a numeral <N>, the outermost call returns a function that will "remember" the next thing passed in and return it after 1 (succ's innermost call) + N + 1 (<N>'s contract) calls.
> Specifically, he calls a numeral system adequate if it allows for a successor (succ) function, predecessor (pred) function, and a zero? function yielding a true (false) encoding when a number is zero (or not).
A numeral system is adequate iff it can be converted to and from Church numerals. Converting from Church numerals requires functions N0 and Nsucc so that
Church2Num c = c Nsucc N0
while converting to Church numerals requires functions Nzero? and Npred so that Num2Church n = Nzero? n C0 (Csucc (Num2Church (Npred n)))
with an implicit use of the fixpoint combinator.An interesting adequate numeral system is what i call the tuple numerals [1], which are simply iterates of the 1-tuple function T = λxλy.y x
So N0 = id, Nsucc = λnλx.n (T x), Npred = λnλx.n x id, and Nzero? = λnλtλf. n (K t) (K f).
These tuple numerals are useful in proving lower bounds on a functional busy beaver [2].
[1] https://github.com/tromp/AIT/blob/master/numerals/tuple_nume...
[2] https://oeis.org/A333479 (see bms.lam link)
[0]: https://bruijn.marvinborner.de/std/Number_Tuple.bruijn.html
Zero = z. s. z
Succ = n. z. s. s n
isZero = n. n True (_. False)
pred = n. n Zero (r. r)
Addition requires explicit recursion, however (since numbers aren't folds), so I guess you'll have to either use Y combinator or closure-convert manually: add' = add'. m. n. m n (r. Succ (add' add' r n))
add = add' add'
In any case, arithmetic operations can't be made fully constant-time for obvious reasons so whether your prefer this to Church numerals is a matter of taste. However, for lists/tuples the ability to execute head/tail/cons in constant time is much more important in practice than being able to do append in constant time.just Scott encoding, Scott-Mogensen refers to a meta encoding of LC in LC. Scott's encoding is fine but requires fixpoint recursion for many operations as you said.
Interestingly though, Mogensen's ternary encoding [1] does not require fixpoint recursion and is the most efficient (wrt being compact) encoding in LC known right now.
> Just use [..], seriously
do you have any further arguments for Scott's encoding? There are many number encodings with constant time predecessor, and with any number requiring O(n) space and `add` being this complex, it becomes quite hard to like
https://projecteuler.net/problem=941
Otherwise, have a go and don’t spoil it! (I have failed thus far.)
Amusingly, this same basic problem was given to me by Google as an interview question. I was baffled, as I could name the problem, and knew of a reference book that covered it; but I wasn't able to just "on the fly" solve it. Felt like I was living a strawman of pointlessly difficult interview questions. (To be fully fair, I'm not sure I bombed this part. Been far too long for me to remember the other parts.)