about summary refs log tree commit diff stats
path: root/js/b/b.js
blob: 04959c458afa3f38d0be9d62983fcdc1a35141b0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/*
//
//  # 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

// curry: Converts a function to its curried form, allowing for partial application.
// pipe: Runs functions from left to right, passing the result of one to the next.
// compose: Runs functions from right to left, passing the result of one to the next.
// identity: Returns whatever you give it as is. Useful for composition...sometimes.
// match: Creates a curried function to match a regular expression in a string.
// replace: Creates a curried function to replace parts of a string, based on a regex or substring.
// filter: Curried array filtering by a predicate function.
// map: Curried array mapping.
// deepMap: Curried recursive mapping for nested arrays or matrices, of any shape.

'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);
    });
  },
};

export default b;