diff options
author | elioat <elioat@tilde.institute> | 2024-08-20 11:24:55 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2024-08-20 11:24:55 -0400 |
commit | e2ff70a282ab2e33d4aaf8c12ca9e5a2cfe4fd91 (patch) | |
tree | d46069f854ef408132efc0d8148a45a936fd23de /js/b | |
parent | 31d8690c1cf880a58d0a4bd11ea344c071bcf7f2 (diff) | |
download | tour-e2ff70a282ab2e33d4aaf8c12ca9e5a2cfe4fd91.tar.gz |
*
Diffstat (limited to 'js/b')
-rw-r--r-- | js/b/b.js | 158 | ||||
-rw-r--r-- | js/b/b.min.js | 4 |
2 files changed, 162 insertions, 0 deletions
diff --git a/js/b/b.js b/js/b/b.js new file mode 100644 index 0000000..5462e93 --- /dev/null +++ b/js/b/b.js @@ -0,0 +1,158 @@ +/* +// +// # The Witch in the Glass +// +// My mother says I must not pass +// Too near that glass; +// She is afraid that I will see +// A little witch that looks like me, +// With a red, red mouth to whisper low +// The very thing I should not know! +// +// Alack for all your mother's care! +// A bird of the air, +// A wistful wind, or (I suppose +// Sent by some hapless boy) a rose, +// With breath too sweet, will whisper low +// The very thing you should not know! +// +// - Sarah Morgan Bryan Piatt +// +*/ + +// b is for useful stuff + +// pipe: Runs functions from left to right. +// compose: Runs functions from right to left. +// identity: Returns whatever you give it as is. +// curry: Converts a function to its curried form. +// match: Creates a curried function to match a regular expression in a string. +// replace: Creates a curried function to replace parts of a string. +// filter: Curried array filtering. +// map: Curried array mapping. +// deepMap: Curried recursive mapping for nested arrays or matrices. + +'use strict' + +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 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: (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value), + + /** + * Composes functions from right to left. + * Takes any number of functions as arguments and returns a function that applies them in sequence from right to left. + * @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(...[].concat(res)), args), + + /** + * A function that returns its input totally and completely unchanged. + * @param {*} x - The input value. + * @returns {*} - The same input value. + */ + identity: x => x, + + /** + * 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: 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: 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: 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: function () { + return this.curry((f, xs) => xs.map(f)); + }, + + /** + * 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: 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'); + +// 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'); + +// 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'); + +// 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/b.min.js b/js/b/b.min.js new file mode 100644 index 0000000..c94132e --- /dev/null +++ b/js/b/b.min.js @@ -0,0 +1,4 @@ +// eli_oat +// docs available in the unminified version +// https://eli.li/_assets/bin/b.js +'use strict';const b={curry:function(fn){const curried=(...args)=>{if(args.length>=fn.length){return fn(...args)}else{return(...rest)=>curried(...args,...rest)}}return curried},pipe:(...fns)=>(value)=>fns.reduce((acc,fn)=>fn(acc),value),compose:(...fns)=>(...args)=>fns.reduceRight((res,fn)=>fn(...[].concat(res)),args),identity:x=>x,match:function(){return this.curry((what,s)=>s.match(what))},replace:function(){return this.curry((what,replacement,s)=>s.replace(what,replacement))},filter:function(){return this.curry((f,xs)=>xs.filter(f))},map:function(){return this.curry((f,xs)=>xs.map(f))},deepMap:function(){return this.curry(function deepMap(f,xs){return Array.isArray(xs)?xs.map((x)=>deepMap(f,x)):f(xs)})}}; \ No newline at end of file |