git.fiddlerwoaroof.com
index.js
d7bc84f6
 export function iota(count, start = 0) {
   const result = [];
   for (let x = 0; x < count; x++) {
     result.push(start + x);
   }
   return result;
 }
 
 export function over(f, ...args) {
   return function (list) {
     return list.map((v) => f(v, ...args));
   };
 }
 
 /**
  * @param {((...args: any[]) => any)[]} funs
  */
 export function juxt(...funs) {
   return function (/** @type {any[]} */ ...args) {
     return funs.map((fun) => fun(...args));
   };
 }
 
 export function compose(...funs) {
   funs = funs.slice();
   return function (...args) {
     let result = funs.pop()(...args);
     while (funs.length > 0) {
       result = funs.pop()(result);
     }
     return result;
   };
 }
 
 export function on(fun, key_fun) {
   return function (data) {
     return fun(key_fun(data));
   };
 }
 
 export function applying(f, ...pos_args) {
   return function (list) {
     return f(...pos_args, ...list);
   };
 }
 
 export function filter(f, ...args) {
   return function (list) {
     return list.filter((v) => f(v, ...args));
   };
 }
 
 export function zip_with(f) {
   return function (lists) {
     const result = [];
     outer: for (let idx = 0; ; idx++) {
       const args = [];
       for (let list of lists) {
         if (idx < list.length) {
           args.push(list[idx]);
         } else {
           break outer;
         }
       }
       result.push(f(...args));
     }
     return result;
   };
 }
 
 export function element(key) {
   return function (it) {
     return it[key];
   };
 }
 
 export function eq(v, eq) {
   if (eq !== undefined) {
     return function (w) {
       return eq(v, w);
     };
   } else {
     return function (w) {
       return v === w;
     };
   }
 }
 
 /**
  * @template T, U
  * @param { (args: T[]) => boolean} cond
  * @param {(args: T[]) => U} fn
  */
 export function applicable_when(cond, fn) {
   return function (/** @type {T} */ data) {
     if (cond(data)) {
       return fn(data);
     } else {
       return data;
     }
   };
 }
 
 /**
  * @param {{ test: (arg0: any) => any; }} regex
  */
 export function matches_regex(regex) {
   return function (string) {
     return regex.test(string);
   };
 }
 
 //TODO: handle maps, at least
 
 /**
  * @param {string | number | symbol} key
  */
 export function key(key) {
   return function (it) {
     return it[key];
   };
 }
 
 /**
  * @param {(...args: any[]) => boolean} fun
  */
 export function complement(fun) {
   return function (...args) {
     return !fun(...args);
   };
 }
 
 /**
  * @param {(a: any) => boolean} pred
  */
 export function include(pred) {
   return function (seq) {
     return seq.filter(pred);
   };
 }
 
 /**
  * @param {(a: any, b: any) => boolean} pred
  */
 export function exclude(pred) {
   const negated = complement(pred);
   return function (seq) {
     return seq.filter(negated);
   };
 }
 
 /**
  * @param {{ [x: string]: any }} keyed
  */
 export function pick(keyed) {
   return function (keys) {
     return keys.map((key) => keyed[key]);
   };
 }
 
 /**
  * @param {(arg0: any, arg1: any) => any} comparator
  * @param {(arg0: any) => any} key
  */
 export function sorted(comparator, key) {
   if (key) {
     return function (seq) {
       const result = seq.slice();
       result.sort((a, b) => {
         return comparator(key(a), key(b)) ? -1 : 1;
       });
       return result;
     };
   } else {
     return function (seq) {
       const result = seq.slice();
       result.sort((a, b) => {
         return comparator(a, b) ? -1 : 1;
       });
       return result;
     };
   }
 }
 
 function matching_list_reducer(test, acc, next) {
   let result;
   if (acc && acc[0] && test(acc[0][0], next[0])) {
     result = [
       [acc[0][0], ...[...acc[0].slice(1), ...next.slice(1)]],
       ...acc.slice(1),
     ];
   } else {
     result = [next, ...(acc || [])];
   }
   return result;
 }
 
 export function combine_matching_lists({ test = (a, b) => a === b } = {}) {
   return function (acc, next) {
     return matching_list_reducer(test, acc, next);
   };
 }
 
 export function cons_new({ test = (a, b) => a === b, key = (v) => v } = {}) {
   return function (acc, next) {
     if (acc && test(key(acc[0]), key(next))) {
       return acc;
     } else {
       return [next, ...acc];
     }
   };
 }
 
 /**
  * @param {{ collector?: ({ test, key }?: { test?: (a: any, b: any) => boolean; key?: (v: any) => any; }) => (acc: any, next: any) => any; test: any; key: any; }} [it]
  */
 export function compress_runs({ collector = cons_new, test, key } = {}) {
   return function (/** @type {any[]} */ it) {
     return it.reduce(collector({ test, key }), []).reverse();
   };
 }
 
 /**
  * @param {number} n
  */
 export function slice(n) {
   return function (/** @type {string | any[]} */ seq) {
     return seq.slice(n);
   };
 }
 
 /**
  * @param {(arg0: any[]) => any} transform
  */
 export function transform_tail(transform) {
   return function ([head, ...tail]) {
     const newTail = transform(tail);
     return [
       head,
       ...(Object.hasOwnProperty.call(newTail, "length") ? newTail : [newTail]),
     ];
   };
 }