908 words
5 minutes
Lambda Calculus via C# (19) Church Encoding and More
TIP

Functional Programming and LINQ via C# Series

Lambda Calculus via C# Series

So far a ton has been encoded. Here is a summary.

Summary of church encoding#

Boolean#

True := λt.λf.t
False := λt.λf.f

Boolean logic#

And := λa.λb.a b False
Or := λa.λb.a True b
Not := λb.b False True
Xor := λa.λb.a (b False True) (b True False)

If logic#

If := λc.λt.λf.c t f (λx.x)

Numeral#

0 := λfx.x ≡ λf.λx.x ≡ λf.λx.f0 x
1 := λfx.f x ≡ λf.λx.f x ≡ λf.λx.f1 x
2 := λfx.f (f x) ≡ λf.λx.(f ∘ f) x ≡ λf.λx.f2 x
3 := λfx.f (f (f x)) ≡ λf.λx.(f ∘ f ∘ f) x ≡ λf.λx.f3 x
...
n := λfx.f (f ... (f x)...) ≡ λf.λx.(f ∘ f ∘ ... ∘ f) x ≡ λf.λx.fn x

Arithmetic#

Increase := λn.λf.λx.f (n f x)
Increase2 := λn.λf.f ∘ (n f)
Add := λa.λb.λf.λx.a f (b f x)
Add2 := λa.λb.λf.fa ∘ fb ≡ λa.λb.λf.(a f) ∘ (b f)
Add3 := λa.λb.a Increase b
Decrease := λn.λf.λx.n (λg.λh.h (g f)) (λu.x) (λu.u)
Decrease2 := λn.Item1 (n (Shift Increase) (CreateTuple 0 0))
Subtract := λa.λb.b Decrease a
Multiply := λa.λb.a (λx.Add b x) 0
_DivideBy := λa.λb.If (IsGreaterOrEqual a b) (λx.Add One (_DivideBy (Subtract a b) b)) (λx.Zero)
DivideByIgnoreZero = λa.λb.If (IsZero b) (λx.0) (λx._DivideBy a b)
Pow := λm.λ e.e (λx.Multiply m x) 1

A better DivideBy will be re-implemented after introducing Y combinator:

DivideBy := Y (λf.λa.λb.If (IsGreaterOrEqual a b) (λx.Add One (f (Subtract a b) b)) (λx.Zero))
≡ (λf.(λx.f (x x)) (λx.f (x x))) (λf.λa.λb.If (IsGreaterOrEqual a b) (λx.Add One (f (Subtract a b) b)) (λx.Zero))

So DivideByIgnoreZero can by redefined using DivideBy instead of _DivideBy:

DivideByIgnoreZero = λa.λb.If (IsZero b) (λx.0) (λx.DivideBy a b)

Predicate#

IsZero := λn.n (λx.False) True

Comparison#

IsLessOrEqual := λa.λb.IsZero (Subtract a b)
IsGreaterOrEqual := λa.λb.IsZero (Subtract b a)
IsEqual := λa.λb.And (IsLessOrEqual a b) (IsGreaterOrEqual a b)
IsLess := λa.λb.Not (IsGreaterOrEqual a b)
IsGreater := λa.λb.Not (IsLessOrEqual a b)
IsNotEqual := λa.λb.Not (IsEqual a b)

Pair (2-tuple)#

CreateTuple := λx.λy.λf.f x y
Tuple := λf.f x y
Item1 := λt.t True
Item2 := λt.t False
Shift := λf.λt.CreateTuple (Item2 t) (f (Item1 t))
Swap := λt.CreateTuple (Item2 t) (Item1 t)

List#

1 pair for each node, and null#

CreateListNode := CreateTuple ≡ λv.λn.λf.f v n
Value := Item1 ≡ λl.l (λv.λn.v)
Next := Item2 ≡ λl.l (λv.λn.n)
Null := False
IsNull := λl.l (λv.λn.λx.False) True
Index := λl.λi.i Next l

2 pairs for each node, and null#

CreateListNode2 := λv.λn.CreateTuple False (CreateTuple v n)
Value2 := λl.Item1 (Item2 l)
Next2 := λl.If (IsNull2 l) (λx.l) (λx.(Item2 (Item2 l)))
Null2 := λf.True
IsNull2 := λl.(Item1 l)
Index2 := λl.λi.i Next2 l

Fold (aggregate) function for each node, and null#

CreateListNode3 := λv.λn.λf.λx.f v (n f x)
Value3 := λl.λx.l (λv.λy.v) x
Next3 := λl.Item2 (l (λv.λt.ShiftTuple (CreateListNode3 v)) (CreateTuple Null3 Null3))
Null3 := λf.λx.x
IsNull3 := λl.l (λv.λx.False) True
Index3 := λl.λi.i Next3 l

Signed number#

Signed := Tuple
ToSigned := λn.CreateTuple n 0
Negate := Swap
Positive := Item1
Negative := Item2
FormatWithZero := λs.If (IsEqual sp sn) (λx.ToSigned 0) (λx.If (IsGreater sp sn) (λy.ToSigned (Subtract sp sn)) (λy.Negate (ToSigned (Subtract sn sp))))

Arithmetic#

AddSigned := λa.λb.FormatWithZero (CreateTuple (Add ap bp) (Add an bn))
SubtractSigned := λa.λb.FormatWithZero (CreateTuple (Add ap bn) (Add an bp))
MultiplySigned := λa.λb.FormatWithZero (CreateTuple (Add (Multiply ap bp) (Multiply an bn)) (Add (Multiply ap bn) (Multiply an bp)))
DivideBySigned := λa.λb.FormatWithZero (CreateTuple (Add (DivideByIgnoreZero ap bp) + (DivideByIgnoreZero an bn)) (Add (DivideByIgnoreZero ap bn) (DivideByIgnoreZero an bp))))

Encode, encode, and encode#

From signed number to complex integer and rational number#

With signed number, complex integer can be encoded by a Church pair of signed numbers: (sreal,simaginary)(s_{real}, s_{imaginary}), which represents complex integer z=sreal+simaginary∗iz = s_{real} + s_{imaginary} * i.

With signed number, rational number can also be encoded by a Church pair of a signed number and a Church numeral: (snumerator,ndenominator)(s_{numerator}, n_{denominator}), which represents rational number:

q=snumerator1+ndenominatorq = \frac{s_{numerator}}{1 + n_{denominator}}

Dyadic rational number can be encoded by (snumerator,nexponent)(s_{numerator}, n_{exponent}) as well, which represents:

d=snumerator2nexponentd = \frac{s_{numerator}}{2 ^ {n_{exponent}}}

From rational number to real number and complex number#

Then with rational number, a real number r can be encoded in many different ways:

  • r can be represented by a sequence of Church pair of 2 rational numbers p0=(q0,q0′)p_{0} = (q_{0}, q_{0}'), p1=(q1,q1′)p_{1} = (q_{1}, q_{1}'), p2=(q2,q2′)p_{2} = (q_{2}, q_{2}'), …, such that:
    • pnp_{n} represents a rational interval, since qnq_{n} and qn′q_{n}' are both rational numbers.
    • pn+1⊆pnp_{n + 1} \subseteq p_{n}
    • lim⁡n→∞qn′−qn=0\lim \limits_{n \to \infty} q_{n}' - q_{n} = 0
    • r=⋂n∈Npnr = \bigcap_{n ∈ N}p_{n}
  • r can be represented by a Cauchy sequence of rational numbers q0, q1, q2, …, and a function f of type Func<_Numeral, _Numeral>, defining the convergence rate of the Cauchy sequence such that:
    • ∀i.j.k.∣qf(i)+j−qf(i)+k∣≤2−i\forall i.j.k. | q_{f(i) + j} - q_{f(i) + k} | ≤ 2 ^ {-i}
    • r=lim⁡n→∞qnr = \lim \limits_{n \to \infty} q_{n}
  • r can be represented by a Cauchy sequence of rational numbers q0, q1, q2, … with a fixed convergence rate, such that:
    • ∀i.j.∣qi−qi+j∣≤1i\forall i.j. | q_{i} - q_{i + j} | ≤ \frac{1}{i}
    • r=lim⁡n→∞qnr = \lim \limits_{n \to \infty} q_{n}

etc.. An example in Haskell can be found on Github.

With real number, complex number can be naturally encoded by a Church pair of 2 real numbers (rreal,rimaginary)(r_{real}, r_{imaginary}), which represents complex number z=rreal+rimaginary∗iz = r_{real} + r_{imaginary} * i.

And much more#

Church pair can encode more complex data structures, like tree.

Church List can encode string.

Church Tuple and Church List can encode more complex algebra types.

…

Don’t worry. The encoding stops here. All the above data types and functions demonstrate that any data type or calculation may be encoded in lambda calculus. This is the Church-Turing thesis.

Lambda Calculus via C# (19) Church Encoding and More
https://codingonwheels.com/posts/lambda-calculus-via-csharp-19-church-encoding-and-more-2017/
Author
Dixin
Published at
2018-11-19
License
CC BY-NC-SA 4.0