Lambda Calculus Implementation in JavaScript
Table of Contents
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.
Lambda Expressions
// Step 1: Understand Lambda Expressions const identity = x => x; console.log(identity(5)); // Output: 5
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
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
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
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
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
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
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
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
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
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.