Lambda Calculus via C# (14) Church Pair (2-Tuple) and Church Numeral Decrease
[LINQ via C# series]
[Lambda Calculus via C# series]
Latest version: https://weblogs.asp.net/dixin/lambda-calculus-via-csharp-4-tuple-and-signed-numeral
In the Church numeral arithmetic part, the Decrease was defined as:
Decrease := λn.λf.λx.n (λg.λh.h (g f)) (λu.x) (λu.u)
This is complex. Now with Church pair (called tuple here to align to C# terms), Decrease can be defined in a easier way.
Shift a Church Pair (2-Tuple)
First, a function is needed to shift a tuple:
Shift = λf.λt.CreateTuple (Item2 t) (f (Item1 t))
It takes a tuple (x, y) and a function f, then returns a new tuple (y, f y).
C# implementation is:
// (x, y) -> (y, f(y)) // Shift = tuple => f => Create(tuple.Item2())(f(tuple.Item1())) public static Tuple<T, T> Shift<T> (this Tuple<T, T> tuple, Func<T, T> f) => Create<T, T>(tuple.Item2())(f(tuple.Item2()));
Again, the implementation is uncurried extension method for convenience of application, and readability.
Decrease a Church numeral
Remember a Church numeral n can be considered to do “Increase” n times from 0:
n Increase Zero
≡ n
What if doing “Shift” n times base on (0, 0)?
3 (Shift Increase) (0, 0)
≡ (Shift Increase) ∘ (Shift Increase) ∘ (Shift Increase) (0, 0)
≡ (Shift Increase) ∘ (Shift Increase) (0, Increase 0)
≡ (Shift Increase) ∘ (Shift Increase) (0, 1)
≡ (Shift Increase) ∘ (1, Increase 1)
≡ (Shift Increase) ∘ (1, 2)
≡ (2, Increase 2)
≡ (2, 3)
And generally:
n (Shift Increase (0, 0))
≡ (n - 1, n)
This turns out a way to get the predecessor of n. So:
Decrease2 := λn.Item1 (n (Shift Increase) (CreateTuple 0 0))
And C#:
public static partial class _NumeralExtensions { // Decrease2 = n => n(tuple => tuple.Shift(Increase))(ChurchTuple.Create(Zero)(Zero)).Item1(); public static _Numeral Decrease2 (this _Numeral numeral) => numeral.Numeral<Tuple<_Numeral, _Numeral>>() (tuple => tuple.Shift(Increase)) // (x, y) -> (y, y + 1) (ChurchTuple.Create<_Numeral, _Numeral>(Zero)(Zero)) .Item1(); }
Unit tests
The following unit tests also shows how to apply the uncurried methods Swap, Shift, _Create:
[TestClass()] public class ChurchTupleTests { [TestMethod()] public void CreateItem1Item2Test() { Tuple<int, string> tuple1 = ChurchTuple.Create<int, string>(1)("a"); Assert.AreEqual(1, tuple1.Item1()); Assert.AreEqual("a", tuple1.Item2()); Tuple<string, int> tuple2 = ChurchTuple.Create<string, int>("a")(1); Assert.AreEqual("a", tuple2.Item1()); Assert.AreEqual(1, tuple2.Item2()); object @object = new object(); Tuple<object, int> tuple3 = ChurchTuple.Create<object, int>(@object)(1); Assert.AreEqual(@object, tuple3.Item1()); Assert.AreEqual(1, tuple3.Item2()); } [TestMethod()] public void ShiftTest() { Tuple<int, int> tuple1 = ChurchTuple.Create<int, int>(1)(2).Shift(_ => _); Assert.AreEqual(2, tuple1.Item1()); Assert.AreEqual(2, tuple1.Item2()); Tuple<int, int> tuple2 = ChurchTuple.Create<int, int>(2)(3).Shift(value => value * 2); Assert.AreEqual(3, tuple2.Item1()); Assert.AreEqual(6, tuple2.Item2()); Tuple<string, string> tuple3 = ChurchTuple.Create<string, string>("a")("b").Shift(value => value + "c"); Assert.AreEqual("b", tuple3.Item1()); Assert.AreEqual("bc", tuple3.Item2()); } [TestMethod()] public void SwapTest() { Tuple<int, string> tuple1 = ChurchTuple.Create<string, int>("a")(1).Swap(); Assert.AreEqual(1, tuple1.Item1()); Assert.AreEqual("a", tuple1.Item2()); Tuple<string, int> tuple2 = ChurchTuple.Create<int, string>(1)("a").Swap(); Assert.AreEqual("a", tuple2.Item1()); Assert.AreEqual(1, tuple2.Item2()); object @object = new object(); Tuple<object, int> tuple3 = ChurchTuple.Create<int, object>(1)(@object).Swap(); Assert.AreEqual(@object, tuple3.Item1()); Assert.AreEqual(1, tuple3.Item2()); } [TestMethod()] public void _CreateTest() { Tuple<int, string> tuple1 = ChurchTuple._Create(1, "a"); Assert.AreEqual(1, tuple1.Item1()); Assert.AreEqual("a", tuple1.Item2()); Tuple<string, int> tuple2 = ChurchTuple._Create("a", 1); Assert.AreEqual("a", tuple2.Item1()); Assert.AreEqual(1, tuple2.Item2()); object @object = new object(); Tuple<object, int> tuple3 = ChurchTuple._Create(@object, 1); Assert.AreEqual(@object, tuple3.Item1()); Assert.AreEqual(1, tuple3.Item2()); } }