Skip to content

Instantly share code, notes, and snippets.

@dlwjiang
Created August 6, 2018 00:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dlwjiang/e3a7d4f1aadfd8b431372a4f30acf43f to your computer and use it in GitHub Desktop.
Save dlwjiang/e3a7d4f1aadfd8b431372a4f30acf43f to your computer and use it in GitHub Desktop.
Y-combinator derivation
/**
* This pretty much works.
* The rest is simplifying and prettifying
* while also extracting the Y-combinator function
* as a generic utility.
*/
const factorial = (f => n => {
if (n < 2) 1;
return n * f(f)(n-1);
})(f => n => {
if (n < 2) return 1;
return n * f(f)(n-1);
})
/**
* Separate out `recur` as a helper function that
* calls itself with itself so we don't have to rewrite
* the recursing logic twice.
*/
const recur = f => f(f);
const factorial2 = recur(f => n => {
if (n < 2) return 1;
return n * f(f)(n-1)
})
/**
* The `f(f)(n-1)` part is kinda ugly so we create
* the `g` function here to abtract that out.
*/
const factorial3 = recur((f) => {
const g = (n) => f(f)(n);
return (n) => {
if (n < 2) return 1;
return n * g(n - 1);
}
})
/**
* Extract both the `wrap` and the `g` function
* into a `wrap` function.
*/
const wrap = (h) => {
return recur(f => {
const g = (n) => f(f)(n);
return h(g);
})
}
const factorial4 = wrap(g => n => {
if (n < 2) return 1;
return n * g(n - 1);
})
/**
* Don't bother naming the `g` function.
* Just inline define it and call it immediately.
*/
const wrap2 = (h) => {
return recur(f => h(n => f(f)(n)));
}
const factorial5 = wrap2(g => n => {
if (n < 2) return 1;
return n * g(n - 1);
})
/**
* Do the same thing for `recur`, just inline it.
* This final version of `wrap` is the Y-combinator.
*/
const Y = (h) => {
return (f => f(f))(f => h(n => f(f)(n)))
}
const almostFactorial = (g) => {
return (n) => {
if (n < 2) return 1;
return n * g(n - 1);
}
}
const factorial6 = Y(almostFactorial)
/**
* Additional
*/
//compact Y-combinator
const Ycompact = (h) => (f => f(f))(f => h(n => f(f)(n)));
const factorial7 = Ycompact(almostFactorial);
//recur abstracted our more readable?
const Yother = (h) => recur(f => h(n => f(f)(n)));
/**
* Testing
*/
console.log(factorial(4));
console.log(factorial2(4));
console.log(factorial3(4));
console.log(factorial4(4));
console.log(factorial5(4));
console.log(factorial6(4));
console.log(factorial7(4));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment