4.5 Numerical coding
In Lambda calculus, there are many methods to encode numerical values, but the most popular method comes from Church, so numerical coding is also called Church number. The idea is that a natural number n is encoded into a function with two parameters, the parameters are f and x, and the function applies f to x n times. Therefore, a function of 0 receives an f and x and returns x (equivalent to applying f 0 times). The function of 1 is applied to f once, and so on.
The method add1 needs to receive a representative of the value n and produce a representative of the value n + 1. In other words, it receives a function with two parameters and returns another function with two parameters; the new function will apply its first parameter to the second parameter n + 1 times. In order for the first n to be applied, the new function should use the old n.
Similar to the encoding of true and false, numerical encoding is also very simple. In order to add two values n and m, we only need to apply add1 to n a total of m times-and m happens to be a function that receives add1 and applies it m times.
The idea of using a value as a function is also very useful for defining iszero. After the function receives a value, it returns true if the value is 0, and other returns false; if this function is applied 0 times less than true, the result is true, otherwise it is false .
In order to generalize the function to equal numbers, we need subtraction. Just like we use add1 to implement addition, subtraction can be implemented with sub1. However, although the add1, add and iszero functions are very simple in Church's book coding, sub1 will appear slightly more complicated. sub1 function receives the value as a parameter, and the n-th application, but its function has to return at least the application function once. Of course, the inverse function of any function cannot be used to reverse an application.
The function that implements sub1 is divided into two parts:
- Pair the given parameter x with true. true indicates that the application of f should be skipped
- Wrap the given function f to receive the pair value, and apply f when the pair value contains false. Must return a pair value containing false to ensure that f will be applied in the future.
The wrap function wraps the given f:
The sub1 function receives a n and returns a new function, the new function receives f and x, wraps f with the wrap function, and encodes x and true, uses n on (wrap f) and ⟨true, x⟩ and extracts The second part of the result-f is applied to x (n-1) times.
Reminder about encoding: the encoding of 0 is consistent with the encoding of false. Therefore, no program can distinguish between 0 and false, and the programmer must ensure that true and false are used only in a Boolean context. This is similar to the implementation of 0, false and null pointers in C language using the same bit values.
Exercise 4.6
Prove that add1 1 = n 2
answer
add1 1 = (λn.λf.λx.f (n f x)) (λf.λx.f x)
→nβ λf.λx.f ((λf.λx.f x) f x)
→nβ λf.λx.f ((λx.f x) x)
→nβ λf.λx.f ((λx.f x) x)
→nβ λf.λx.f (f x) = 2
Exercise 4.7
Prove that iszero 1 = n false
answer
iszero 1 = λn.n (λx.false) true (λf.λx.f x)
→nβ (λf.λx.f x) (λx.false) true
→nβ (λx.(λx.false) x) true
→nβ (λx.false) true
→nβ false
Exercise 4.8
Prove that sub1 1 = n 0
answer
sub1 1 = (λn.λf.λx.snd (n (wrap f) ⟨true, x⟩)) (λf.λx.f x)
→nβ λf.λx.snd ((λf.λx.f x) (wrap f) ⟨true, x⟩)
→nβ λf.λx.snd (λx.(wrap f) x)⟨true, x⟩)
→nβ λf.λx.snd ((wrap f) ⟨true, x⟩)
= λf.λx.snd (((λf.λp.⟨false, if (fst p) (snd p) (f (snd p))⟩) f) ⟨true, x⟩)
→nβ λf.λx.snd ((λp.⟨false, if (fst p) (snd p) (f (snd p))⟩) ⟨true, x⟩)
→nβ λf.λx.snd (⟨false, if (fst ⟨true, x⟩) (snd ⟨true, x⟩) (f (snd ⟨true, x⟩))⟩)
→→n λf.λx.snd (⟨false, if true (snd ⟨true, x⟩) (f (snd ⟨true, x⟩))⟩
→→n λf.λx.snd (⟨false, snd ⟨true, x⟩)⟩
→→n λf.λx.snd ⟨false, x⟩
→→n λf.λx.x
= 0
Exercise 4.9
Define mult in a way that helps us implement add. In other words, to achieve (mult nm), use the fact that n itself applies the function n times, and apply m to 0 n additions. (Hint: What type of value is (add m)?)
answer
mult ≐ λn.λm.λf.m (n f)
Exercise 4.10
Lambda calculus does not provide an error signal mechanism. What will happen if sub1 is applied to 0? What happens when iszero is applied to true?
answer
-
sub1 0 = (λn.λf.λx.snd (n (wrap f) ⟨true, x⟩)) (λf.λx.x)
→nβ λf.λx.snd ((λf.λx.x) (wrap f) ⟨true, x⟩)
→nβ λf.λx.snd ((λx.x) ⟨true, x⟩)
→nβ λf.λx.snd ⟨true, x⟩
→→n λf.λx.x = 0
-
iszero true = (λn.n (λx.false) true) (λx.λy.x)
→nβ (λx.λy.x) (λx.false) true
→nβ λy.λx.false true
→nβ λx.false