From dbdf6afa27fe2f706b30fabb48807b5064ee3fba Mon Sep 17 00:00:00 2001 From: Vladimir Gorej Date: Wed, 27 Dec 2017 17:15:40 +0100 Subject: [PATCH] feat: add Y combinator Closes #130 --- src/Y.js | 30 ++++++++++++++++++++++++++++++ src/index.d.ts | 9 +++++++++ src/index.js | 1 + test/Y.js | 16 ++++++++++++++++ 4 files changed, 56 insertions(+) create mode 100644 src/Y.js create mode 100644 test/Y.js diff --git a/src/Y.js b/src/Y.js new file mode 100644 index 0000000000..cbc049be19 --- /dev/null +++ b/src/Y.js @@ -0,0 +1,30 @@ +/** + * Y-combinator + * + * The Y combinator is an interesting function which only works with functional languages, + * showing how recursion can still be done even without any variable or function declarations, + * only functions and parameters + * + * @func Y + * @memberOf RA + * @since {@link https://char0n.github.io/ramda-adjunct/2.3.0|v2.3.0} + * @category Function + * @sig (a, ... -> b -> b) -> (a, ... -> b) + * @param {Function} le Recursive function maker + * @return {Function} + * @see {@link http://kestas.kuliukas.com/YCombinatorExplained/|Y combinator explained} + * @example + * + * const makeFact = givenFact => (n) => { + * if (n < 2) { return 1 } + * return n * givenFact(n - 1); + * }; + * + * const factorial = RA.Y(makeFact); + * + * factorial(5); //=> 120 + */ + +const Y = le => (f => f(f))(g => le(x => (g(g))(x))); + +export default Y; diff --git a/src/index.d.ts b/src/index.d.ts index 984b3dc159..a13e8cbb78 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -659,6 +659,15 @@ declare namespace RamdaAdjunct { defaultWhen(predicate: Function, defaultVal: DefVal): (val: Val) => DefVal | Val; defaultWhen(predicate: Function): (defaultVal: DefVal) => (val: Val) => DefVal | Val; + /** + * Y-combinator + * + * The Y combinator is an interesting function which only works with functional languages, + * showing how recursion can still be done even without any variable or function declarations, + * only functions and parameters + */ + Y(le: Function): Function; + /** * Identity type. */ diff --git a/src/index.js b/src/index.js index 9a527a44be..8af84efb7e 100644 --- a/src/index.js +++ b/src/index.js @@ -80,6 +80,7 @@ export { default as curryRightN } from './curryRightN'; export { default as curryRight } from './curryRight'; export { default as resolveP } from './resolveP'; export { default as rejectP } from './rejectP'; +export { default as Y } from './Y'; // List export { default as pickIndexes } from './pickIndexes'; export { default as list } from './list'; diff --git a/test/Y.js b/test/Y.js new file mode 100644 index 0000000000..6461935bca --- /dev/null +++ b/test/Y.js @@ -0,0 +1,16 @@ +import * as RA from '../src/index'; +import eq from './shared/eq'; + + +describe('Y', function() { + it('tests for making a factorial function', function() { + const makeFact = givenFact => (n) => { + if (n < 2) { return 1 } + return n * givenFact(n - 1); + }; + + const factorial = RA.Y(makeFact); + + eq(factorial(5), 120); + }); +});