Lambda Calculus Implementation in JavaScript
Table of Contents
1. Introduction
This org-mode file contains a Lambda Calculus implementation in JavaScript. Each section includes self-contained code blocks that can be run independently in a JavaScript environment.
2. Lambda Expressions
// Step 1: Understand Lambda Expressions
const identity = x => x;
console.log(identity(5));
// Output: 5
3. Church Booleans
// Step 2: Implement Church Booleans
const lcTrue = x => y => x;
const lcFalse = x => y => y;
const lcIf = condition => then => else_ => condition(then)(else_);
console.log(lcIf(lcTrue)("yes")("no"));
// Output: yes
4. Basic Combinators
// Step 3: Implement Basic Combinators
const I = x => x;
const K = x => y => x;
const KI = x => y => y;
console.log(I(5));
console.log(K(3)(4));
console.log(KI(3)(4));
// Output:
// 5
// 3
// 4
5. Church Numerals
// Step 4: Create Church Numerals
const lcZero = f => x => x;
const lcSucc = n => f => x => f(n(f)(x));
const churchToInt = n => n(x => x + 1)(0);
const lcOne = lcSucc(lcZero);
const lcTwo = lcSucc(lcOne);
console.log(churchToInt(lcZero));
console.log(churchToInt(lcOne));
console.log(churchToInt(lcTwo));
// Output:
// 0
// 1
// 2
6. Basic Arithmetic
// Step 5: Implement Basic Arithmetic
const lcZero = f => x => x;
const lcSucc = n => f => x => f(n(f)(x));
const churchToInt = n => n(x => x + 1)(0);
const lcAdd = m => n => f => x => m(f)(n(f)(x));
const lcMult = m => n => f => m(n(f));
const lcOne = lcSucc(lcZero);
const lcTwo = lcSucc(lcOne);
const lcThree = lcSucc(lcTwo);
console.log(churchToInt(lcAdd(lcOne)(lcTwo)));
console.log(churchToInt(lcMult(lcTwo)(lcThree)));
// Output:
// 3
// 6
7. Pairs
// Step 6: Implement Pairs
const lcPair = x => y => f => f(x)(y);
const lcFirst = p => p(x => y => x);
const lcSecond = p => p(x => y => y);
const myPair = lcPair(3)(4);
console.log(lcFirst(myPair));
console.log(lcSecond(myPair));
// Output:
// 3
// 4
8. Lists
// Step 7: Build Lists Using Pairs
const lcTrue = x => y => x;
const lcFalse = x => y => y;
const lcPair = x => y => f => f(x)(y);
const lcFirst = p => p(x => y => x);
const lcSecond = p => p(x => y => y);
const lcNil = x => lcTrue;
const lcCons = lcPair;
const lcIsNil = l => l(h => t => lcFalse);
const lcHead = lcFirst;
const lcTail = lcSecond;
// Helper function to convert JavaScript array to Church-encoded list
const listToChurch = arr => {
if (arr.length === 0) return lcNil;
return lcCons(arr[0])(listToChurch(arr.slice(1)));
};
// Helper function to convert Church-encoded list to JavaScript array
const churchToList = l => {
const result = [];
let current = l;
while (lcIsNil(current)(false)(true)) {
result.push(lcHead(current));
current = lcTail(current);
}
return result;
};
const myList = listToChurch([1, 2, 3]);
console.log(churchToList(myList));
console.log(lcHead(myList));
console.log(churchToList(lcTail(myList)));
console.log(lcIsNil(myList)(true)(false));
console.log(lcIsNil(lcNil)(true)(false));
// Output:
// [1, 2, 3]
// 1
// [2, 3]
// false
// true
9. Comparison Operations
// Step 8: Implement Comparison Operations
const lcZero = f => x => x;
const lcSucc = n => f => x => f(n(f)(x));
const lcTrue = x => y => x;
const lcFalse = x => y => y;
const lcIsZero = n => n(x => lcFalse)(lcTrue);
const lcLeq = m => n => lcIsZero(lcSub(m)(n));
const lcEq = m => n => lcAnd(lcLeq(m)(n))(lcLeq(n)(m));
const lcAnd = x => y => x(y)(lcFalse);
const lcSub = m => n => n(n => f => x => n(g => h => h(g(f)))(y => x)(y => y))(m);
const lcOne = lcSucc(lcZero);
const lcTwo = lcSucc(lcOne);
console.log(lcIsZero(lcZero)(true)(false));
console.log(lcIsZero(lcOne)(true)(false));
console.log(lcLeq(lcOne)(lcTwo)(true)(false));
console.log(lcEq(lcOne)(lcOne)(true)(false));
console.log(lcEq(lcOne)(lcTwo)(true)(false));
// Output:
// true
// false
// true
// true
// false
10. Higher-Order List Operations
// Step 9: Implement Higher-Order List Operations
const lcZero = f => x => x;
const lcSucc = n => f => x => f(n(f)(x));
const lcTrue = x => y => x;
const lcFalse = x => y => y;
const lcPair = x => y => f => f(x)(y);
const lcFirst = p => p(x => y => x);
const lcSecond = p => p(x => y => y);
const lcNil = x => lcTrue;
const lcCons = lcPair;
const lcIsNil = l => l(h => t => lcFalse);
const lcHead = lcFirst;
const lcTail = lcSecond;
const lcIf = condition => then => else_ => condition(then)(else_);
const lcMap = f => l => lcIf(lcIsNil(l))
(lcNil)
(() => lcCons(f(lcHead(l)))(lcMap(f)(lcTail(l))))();
const lcFilter = p => l => lcIf(lcIsNil(l))
(lcNil)
(() => lcIf(p(lcHead(l)))
(() => lcCons(lcHead(l))(lcFilter(p)(lcTail(l))))
(() => lcFilter(p)(lcTail(l))))();
const lcFold = f => acc => l => lcIf(lcIsNil(l))
(acc)
(() => lcFold(f)(f(acc)(lcHead(l)))(lcTail(l)))();
const listToChurch = arr => {
if (arr.length === 0) return lcNil;
return lcCons(arr[0])(listToChurch(arr.slice(1)));
};
const churchToList = l => {
const result = [];
let current = l;
while (lcIsNil(current)(false)(true)) {
result.push(lcHead(current));
current = lcTail(current);
}
return result;
};
const myList = listToChurch([1, 2, 3]);
const doubledList = lcMap(x => x * 2)(myList);
console.log("Doubled list:", churchToList(doubledList));
const filteredList = lcFilter(x => x > 1)(myList);
console.log("Filtered list:", churchToList(filteredList));
const sumList = lcFold(x => y => x + y)(0)(myList);
console.log("Sum of list:", sumList);
// Output:
// Doubled list: [2, 4, 6]
// Filtered list: [2, 3]
// Sum of list: 6
11. Recursion and Fixed-Point Combinators
// Step 10: Explore Recursion and Fixed-Point Combinators
const lcZero = f => x => x;
const lcSucc = n => f => x => f(n(f)(x));
const lcTrue = x => y => x;
const lcFalse = x => y => y;
const lcIf = condition => then => else_ => condition(then)(else_);
const lcIsZero = n => n(x => lcFalse)(lcTrue);
const lcSub = m => n => n(n => f => x => n(g => h => h(g(f)))(y => x)(y => y))(m);
const lcMult = m => n => f => m(n(f));
const churchToInt = n => n(x => x + 1)(0);
const lcOne = lcSucc(lcZero);
const Y = f => (x => f(y => x(x)(y)))(x => f(y => x(x)(y)));
const factorial = Y(f => n => lcIf(lcIsZero(n))
(lcOne)
(() => lcMult(n)(f(lcSub(n)(lcOne))))());
const lcFive = lcSucc(lcSucc(lcSucc(lcSucc(lcOne))));
console.log("Factorial of 5:", churchToInt(factorial(lcFive)));
// Output:
// Factorial of 5: 120
12. Conclusion
This org-mode file provides a comprehensive implementation of Lambda Calculus in JavaScript, including Church encodings for booleans, numerals, and lists, as well as higher-order functions and recursion using the Y combinator. Each section can be run independently in a JavaScript environment (such as a browser console) to explore different aspects of Lambda Calculus.