about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--js/b.js122
-rw-r--r--js/b.min.js1
2 files changed, 71 insertions, 52 deletions
diff --git a/js/b.js b/js/b.js
index 459c79f..5462e93 100644
--- a/js/b.js
+++ b/js/b.js
@@ -36,12 +36,28 @@
 
 const b = {
   /**
+   * Converts a function into a curried function, allowing for partial application.
+   * A curried function can be partially applied and will return a new function until all arguments are provided.
+   * @param {Function} fn - The function to curry.
+   * @returns {Function} - The curried function.
+   */
+  curry: function (fn) {
+    const curried = (...args) => {
+      if (args.length >= fn.length)
+        return fn(...args)
+      else
+        return (...rest) => curried(...args, ...rest)
+    }
+    return curried
+  },
+
+  /**
    * Composes functions from left to right.
-   * Takes any number of functions as arguments and returns the result of applying them in sequence.
-   * @param {...Function} args - The functions to be composed.
-   * @returns {Function} - A function that applies the composed functions from left to right.
+   * Takes any number of functions as arguments and returns a function that applies them in sequence to a supplied value.
+   * @param {...Function} fns - The functions to be composed.
+   * @returns {Function} - A function that takes an initial value and applies the composed functions from left to right.
    */
-  pipe: (...args) => args.reduce((acc, el) => el(acc)),
+  pipe: (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value),
 
   /**
    * Composes functions from right to left.
@@ -49,92 +65,94 @@ const b = {
    * @param {...Function} fns - The functions to be composed.
    * @returns {Function} - A function that applies the composed functions from right to left.
    */
-  compose: (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0],
+  compose: (...fns) => (...args) => fns.reduceRight((res, fn) => fn(...[].concat(res)), args),
 
   /**
-   * A function that returns its input unmodified.
+   * A function that returns its input totally and completely unchanged.
    * @param {*} x - The input value.
    * @returns {*} - The same input value.
    */
   identity: x => x,
 
   /**
-   * Converts a function into a curried function.
-   * A curried function can be partially applied and will return a new function until all arguments are provided.
-   * @param {Function} fn - The function to curry.
-   * @returns {Function} - The curried function.
-   */
-  curry: (fn) => {
-    const curried = (...args) => {
-      if (args.length >= fn.length)
-        return fn(...args)
-      else
-        return (...rest) => curried(...args, ...rest)
-    }
-    return curried
-  },
-
-  /**
    * Curried function that matches a regular expression against a string.
    * @returns {Function} - A curried function that takes a regex and a string and returns the match result.
    */
-  match: () => b.curry((what, s) => s.match(what)),
+  match: function () {
+    return this.curry((what, s) => s.match(what));
+  },
 
   /**
    * Curried function that replaces parts of a string based on a regex or substring.
    * @returns {Function} - A curried function that takes a regex or substring, a replacement, and a string, and returns the replaced string.
    */
-  replace: () => b.curry((what, replacement, s) => s.replace(what, replacement)),
+  replace: function () {
+    return this.curry((what, replacement, s) => s.replace(what, replacement));
+  },
 
   /**
    * Curried function that filters an array based on a predicate function.
    * @returns {Function} - A curried function that takes a predicate function and an array, and returns the filtered array.
    */
-  filter: () => b.curry((f, xs) => xs.filter(f)),
+  filter: function () {
+    return this.curry((f, xs) => xs.filter(f));
+  },
 
   /**
    * Curried function that maps a function over an array.
    * @returns {Function} - A curried function that takes a mapping function and an array, and returns the mapped array.
    */
-  map: () => b.curry((f, xs) => xs.map(f)),
+  map: function () {
+    return this.curry((f, xs) => xs.map(f));
+  },
 
   /**
-   * Curried function that recursively maps a function over an array or matrix of any depth.
+   * Curried function that recursively maps a function over an array or matrix of any shape.
    * @returns {Function} - A curried function that takes a mapping function and a nested array, and returns the deeply mapped array.
    */
-  deepMap: () =>
-    b.curry(function deepMap(f, xs) {
+  deepMap: function () {
+    return this.curry(function deepMap(f, xs) {
       return Array.isArray(xs)
         ? xs.map((x) => deepMap(f, x))
         : f(xs);
-    }),
+    });
+  },
 };
 
+// Tests! 
+// pipe
+const addOne = (x) => x + 1;
+const double = (x) => x * 2;
+console.assert(b.pipe(addOne, double)(3) === 8, 'Test for pipe failed');
+
+// compose
+console.assert(b.compose(double, addOne)(3) === 8, 'Test for compose failed');
+
+// identity
+console.assert(b.identity(5) === 5, 'Test for identity failed');
 
+// curry
+const add = (x, y) => x + y;
+const curriedAdd = b.curry(add);
+console.assert(curriedAdd(3)(4) === 7, 'Test for curry failed');
 
-// // pipe
-// const title = '10 Weird Facts About Dogs';
-// const toLowerCase = (str) => str.toLowerCase();
-// const addHyphens = (str) => str.replace(/\s/g, '-');
-// const reverseText = (str) => (str === '') ? '' : reverseText(str.substr(1)) + str.charAt(0);
-// const slug = b.pipe(title, toLowerCase, addHyphens, reverseText);
-// console.log('pipe ', slug);
+// match
+const matchDigits = b.match()(/\d+/g);
+console.assert(JSON.stringify(matchDigits('a1b2c3')) === JSON.stringify(['1', '2', '3']), 'Test for match failed');
 
+// replace
+const censor = b.replace()(/badword/g, '****');
+console.assert(censor('This is a badword in a sentence.') === 'This is a **** in a sentence.', 'Test for replace failed');
 
-// // compose 
-// const toUpperCase = x => x.toUpperCase();
-// const exclaim = x => `${x}!`;
-// const shout = b.compose(exclaim, toUpperCase);
-// const ret = shout('send in the clowns'); // "SEND IN THE CLOWNS!"
-// console.log('compose ', ret);
+// filter
+const isEven = (x) => x % 2 === 0;
+const filterEvens = b.filter()(isEven);
+console.assert(JSON.stringify(filterEvens([1, 2, 3, 4])) === JSON.stringify([2, 4]), 'Test for filter failed');
 
+// map
+const mapDoubles = b.map()(double);
+console.assert(JSON.stringify(mapDoubles([1, 2, 3])) === JSON.stringify([2, 4, 6]), 'Test for map failed');
 
-// // curry family
-// const hasLetterR = b.match(/r/g);
-// const r1 = hasLetterR('hello world');
-// const r2 = hasLetterR('just j and s and t etc');
-// const r3 = b.filter(hasLetterR, ['rock and roll', 'smooth jazz']);
-// const noVowels = b.replace(/[aeiou]/ig);
-// const censored = noVowels('*');
-// const r4 = censored('Chocolate Rain');
-// console.log('curry ', r1, r2, r3, r4);
\ No newline at end of file
+// deepMap
+const nestedArray = [1, [2, [3, 4]], [5, 6]];
+console.assert(JSON.stringify(b.deepMap()(double, nestedArray)) === JSON.stringify([2, [4, [6, 8]], [10, 12]]), 'Test for deepMap failed');
\ No newline at end of file
diff --git a/js/b.min.js b/js/b.min.js
new file mode 100644
index 0000000..1a5647b
--- /dev/null
+++ b/js/b.min.js
@@ -0,0 +1 @@
+'use strict';const b={pipe:(...args)=>args.reduce((acc,el)=>el(acc)),compose:(...fns)=>(...args)=>fns.reduceRight((res,fn)=>[fn.call(null,...res)],args)[0],identity:x=>x,curry:(fn)=>{const curried=(...args)=>{if(args.length>=fn.length){return fn(...args)}else{return(...rest)=>curried(...args,...rest)}}return curried},match:()=>b.curry((what,s)=>s.match(what)),replace:()=>b.curry((what,replacement,s)=>s.replace(what,replacement)),filter:()=>b.curry((f,xs)=>xs.filter(f)),map:()=>b.curry((f,xs)=>xs.map(f)),deepMap:()=>b.curry(function deepMap(f,xs){return Array.isArray(xs)?xs.map((x)=>deepMap(f,x)):f(xs)})};
\ No newline at end of file