I'm trying to 'implement' Church's encoding of lambda calculus in Javascript, but started having trouble when I wrote the factorial function:
const factorial = n => (iszero(n))(ONE)(multiply(n)(factorial(predecessor(n))));
iszero(n) acts as a conditional, and returns a function that executes it's first parameter if n is zero, or the second if it isn't.
Calling this function on any value results in a stack overflow.
I tried to simplify it to find out why:
//const ifelse = condition => a => b => condition ? a : b;
//const factorial = n => ifelse(n == 0)(1)(n * factorial(n - 1));
const ifelse = function(condition, a, b) {
if (condition) {
return a;
} else {
return b;
}
}
const factorial = function(number) {
return ifelse(number == 0, 1, number * factorial(number - 1));
}
calling factorial here also results in overflow, although if we reduce the ifelse function in factorial, it makes a perfectly functional factorial function that doesn't throw:
//const factorial = n => (n == 0) ? (1) : (n * factorial(n - 1));
const factorial = function(number) {
if (number == 0) {
return 1;
} else {
return number * factorial(number - 1);
}
}
But I'm trying to use nothing but functions inside the factorial, so the ternary conditional operator is not acceptable (see the commented arrow notation).
Why is my factorial function resulting in a stack overflow when invoked on any value, and can this be avoided while still using only functions (no conditionals)?
EDIT: the definitions for the first piece of code:
const TRUE = x => y => x;
const FALSE = x => y => y;
const ZERO = f => x => x;
const ONE = f => x => f(x);
const pair = a => b => f => f(a)(b);
const first = p => p(TRUE);
const second = p => p(FALSE);
const iszero = n => n(x => FALSE)(TRUE);
const successor = n => f => x => f(n(f)(x));
const multiply = n1 => n2 => f => x => n1(n2(f))(x);
const predecessor = n => second(n(p => pair(successor(first(p)))(first(p)))(pair(ZERO)(ZERO)));