functionalscript 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import * as Operator from '../../types/function/operator/module.f.ts';
1
+ import type * as Operator from '../../types/function/operator/module.f.ts';
2
2
  type Reduce = Operator.Reduce<bigint>;
3
3
  type Unary = Operator.Unary<bigint, bigint>;
4
4
  /**
@@ -1,5 +1,4 @@
1
- import * as Operator from "../../types/function/operator/module.f.js";
2
- import { scalar_mul } from "../../types/bigint/module.f.js";
1
+ import { repeat } from "../../types/monoid/module.f.js";
3
2
  /**
4
3
  * Creates a prime field with the specified prime modulus and associated operations.
5
4
  *
@@ -33,7 +32,7 @@ export const prime_field = p => {
33
32
  };
34
33
  const middle = p >> 1n;
35
34
  const pow2 = a => mul(a)(a);
36
- const pow = scalar_mul({ 0: 1n, add: mul });
35
+ const pow = repeat({ identity: 1n, operation: mul });
37
36
  return {
38
37
  p,
39
38
  middle,
@@ -1,4 +1,4 @@
1
- import * as Operator from '../../types/function/operator/module.f.ts';
1
+ import type * as Operator from '../../types/function/operator/module.f.ts';
2
2
  import { type PrimeField } from '../prime_field/module.f.ts';
3
3
  /**
4
4
  * A 2D point represented as a pair of `bigint` values `[x, y]`.
@@ -1,6 +1,5 @@
1
- import * as Operator from "../../types/function/operator/module.f.js";
2
1
  import { prime_field, sqrt } from "../prime_field/module.f.js";
3
- import { scalar_mul } from "../../types/bigint/module.f.js";
2
+ import { repeat } from "../../types/monoid/module.f.js";
4
3
  /**
5
4
  * Constructs an elliptic curve with the given initialization parameters.
6
5
  *
@@ -71,7 +70,7 @@ export const curve = ({ p, a: [a0, a1], n }) => {
71
70
  return [x, neg(y)];
72
71
  },
73
72
  add: addPoint,
74
- mul: scalar_mul({ 0: null, add: addPoint })
73
+ mul: repeat({ identity: null, operation: addPoint })
75
74
  };
76
75
  };
77
76
  export const eq = a => b => {
@@ -7,7 +7,7 @@ type Attributes = {
7
7
  readonly [k in string]: string;
8
8
  };
9
9
  export type Node = Element | string;
10
- export declare const element: (element: Element) => List<string>;
10
+ export declare const element: (e: Element) => List<string>;
11
11
  export declare const html: (_: Element) => List<string>;
12
12
  export declare const htmlToString: (_: Element) => string;
13
13
  export {};
package/html/module.f.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { map, flatMap, flat, concat as listConcat } from "../types/list/module.f.js";
2
2
  import { concat as stringConcat } from "../types/string/module.f.js";
3
- import * as O from "../types/object/module.f.js";
4
3
  import { compose } from "../types/function/module.f.js";
5
4
  import * as utf16 from "../text/utf16/module.f.js";
6
5
  const { stringToList } = utf16;
@@ -27,11 +26,10 @@ const voidTagList = [
27
26
  'track',
28
27
  'wbr',
29
28
  ];
30
- const isVoid = tag => voidTagList.includes(tag);
31
29
  /**
32
30
  * https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-in-html
33
31
  */
34
- const escapeCharCode = code => {
32
+ const escapeCharCode = (code) => {
35
33
  switch (code) {
36
34
  case 0x22: return '&quot;';
37
35
  case 0x26: return '&amp;';
@@ -41,18 +39,24 @@ const escapeCharCode = code => {
41
39
  }
42
40
  };
43
41
  const escape = compose(stringToList)(map(escapeCharCode));
44
- const node = n => typeof n === 'string' ? escape(n) : element(n);
42
+ const node = (n) => typeof n === 'string' ? escape(n) : element(n);
45
43
  const nodes = flatMap(node);
46
44
  const attribute = ([name, value]) => flat([[' ', name, '="'], escape(value), ['"']]);
47
45
  const attributes = compose(entries)(flatMap(attribute));
48
- const open = t => a => flat([[`<`, t], attributes(a), [`>`]]);
49
- const element3 = t => ([a, n]) => {
50
- const o = flat([[`<`, t], attributes(a), [`>`]]);
51
- return isVoid(t) ? o : flat([o, nodes(n), ['</', t, '>']]);
46
+ const parseElement = (e) => {
47
+ const [tag, item1, ...list] = e;
48
+ return item1 === undefined ?
49
+ [tag, {}, []] :
50
+ typeof item1 === 'object' && !(item1 instanceof Array) ?
51
+ [tag, item1, list] :
52
+ [tag, {}, [item1, ...list]];
52
53
  };
53
- export const element = e => {
54
- const [t, a, ...n] = e;
55
- return element3(t)(a === undefined ? [{}, []] : typeof a === 'object' && !(a instanceof Array) ? [a, n] : [{}, [a, ...n]]);
54
+ export const element = (e) => {
55
+ const [tag, a, n] = parseElement(e);
56
+ const open = flat([[`<`, tag], attributes(a), [`>`]]);
57
+ return voidTagList.includes(tag) ?
58
+ open :
59
+ flat([open, nodes(n), ['</', tag, '>']]);
56
60
  };
57
61
  export const html = compose(element)(listConcat(['<!DOCTYPE html>']));
58
62
  export const htmlToString = compose(html)(stringConcat);
package/html/test.f.js CHANGED
@@ -1,40 +1,40 @@
1
- import * as _ from "./module.f.js";
1
+ import { htmlToString } from "./module.f.js";
2
2
  export default {
3
3
  empty: () => {
4
- const r = _.htmlToString(['html']);
4
+ const r = htmlToString(['html']);
5
5
  if (r !== '<!DOCTYPE html><html></html>') {
6
6
  throw `empty: ${r}`;
7
7
  }
8
8
  },
9
9
  empty2: () => {
10
- const r = _.htmlToString(['html']);
10
+ const r = htmlToString(['html']);
11
11
  if (r !== '<!DOCTYPE html><html></html>') {
12
12
  throw r;
13
13
  }
14
14
  },
15
15
  void: () => {
16
- const r = _.htmlToString(['area']);
16
+ const r = htmlToString(['area']);
17
17
  if (r !== '<!DOCTYPE html><area>') {
18
18
  throw r;
19
19
  }
20
20
  },
21
21
  some: () => {
22
22
  const x = ['div', {}, '<div>&amp;</div>', ['a', { href: 'hello"' }]];
23
- const s = _.htmlToString(x);
23
+ const s = htmlToString(x);
24
24
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
25
25
  throw s;
26
26
  }
27
27
  },
28
28
  some2: () => {
29
29
  const x = ['div', '<div>&amp;</div>', ['a', { href: 'hello"' }]];
30
- const s = _.htmlToString(x);
30
+ const s = htmlToString(x);
31
31
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
32
32
  throw s;
33
33
  }
34
34
  },
35
35
  someVoid: () => {
36
36
  const x = ['div', ['br', { id: '5' }], '<div>&amp;</div>', ['a', { href: 'hello"' }]];
37
- const s = _.htmlToString(x);
37
+ const s = htmlToString(x);
38
38
  if (s !== '<!DOCTYPE html><div><br id="5">&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
39
39
  throw s;
40
40
  }
@@ -1,5 +1,5 @@
1
1
  import * as list from '../../types/list/module.f.ts';
2
- import * as bigfloatT from '../../types/bigfloat/module.f.ts';
2
+ import type * as bigfloatT from '../../types/bigfloat/module.f.ts';
3
3
  export type StringToken = {
4
4
  readonly kind: 'string';
5
5
  readonly value: string;
@@ -7,7 +7,6 @@ const { at } = map;
7
7
  import * as _range from "../../types/range/module.f.js";
8
8
  const { one } = _range;
9
9
  const { empty, stateScan, flat, toArray, reduce: listReduce, scan } = list;
10
- import * as bigfloatT from "../../types/bigfloat/module.f.js";
11
10
  const { fromCharCode } = String;
12
11
  import * as ascii from "../../text/ascii/module.f.js";
13
12
  const { range } = ascii;
@@ -23,5 +23,33 @@ declare const _default: {
23
23
  object: () => void;
24
24
  };
25
25
  };
26
+ unary_plus: () => {
27
+ null: () => void;
28
+ undefined: () => void;
29
+ boolean: {
30
+ false: () => void;
31
+ true: () => void;
32
+ };
33
+ number: {
34
+ zero: () => void;
35
+ positive: () => void;
36
+ negative: () => void;
37
+ };
38
+ string: {
39
+ empty: () => void;
40
+ zero: () => void;
41
+ positive: () => void;
42
+ nan: () => void;
43
+ };
44
+ array: {
45
+ empty: () => void;
46
+ single_number: () => void;
47
+ single_string: () => void;
48
+ multiple: () => void;
49
+ };
50
+ object: {
51
+ empty: () => void;
52
+ };
53
+ };
26
54
  };
27
55
  export default _default;
@@ -25,6 +25,7 @@ export default {
25
25
  },
26
26
  nullish: () => {
27
27
  n(false)(undefined);
28
+ n(false)(null);
28
29
  }
29
30
  },
30
31
  number: {
@@ -80,5 +81,49 @@ export default {
80
81
  n(o)({ '0': '0' });
81
82
  }
82
83
  }
84
+ },
85
+ unary_plus: () => {
86
+ const op = (n) => +n;
87
+ const nan = (n) => {
88
+ let result = op(n);
89
+ if (!Number.isNaN(result)) {
90
+ throw result;
91
+ }
92
+ };
93
+ return {
94
+ null: () => e(op(null))(0),
95
+ undefined: () => nan(undefined),
96
+ boolean: {
97
+ false: () => e(op(false))(0),
98
+ true: () => e(op(true))(1)
99
+ },
100
+ number: {
101
+ zero: () => e(op(0))(0),
102
+ positive: () => e(op(2.3))(2.3),
103
+ negative: () => e(op(-2.3))(-2.3)
104
+ },
105
+ string: {
106
+ empty: () => e(op(""))(0),
107
+ zero: () => e(op("0"))(0),
108
+ positive: () => e(op("2.3"))(2.3),
109
+ nan: () => nan("a")
110
+ },
111
+ // TODO: bigint - handle TypeError exception for bigint. The test below (that follows
112
+ // current Rust implementation) is incorrect.
113
+ // bigint: {
114
+ // nan: () => u_p_nan(0n)
115
+ // }
116
+ array: {
117
+ empty: () => e(op([]))(0),
118
+ single_number: () => e(op([2.3]))(2.3),
119
+ single_string: () => e(op(["-2.3"]))(-2.3),
120
+ multiple: () => nan([null, null])
121
+ },
122
+ object: {
123
+ empty: () => nan({})
124
+ // TODO: test objects with valueOf, toString functions - when Rust logic is implemented
125
+ }
126
+ // TODO: test Function - when Rust logic is implemented
127
+ };
83
128
  }
84
129
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "**/*.f.d.ts",
@@ -1,21 +1,24 @@
1
1
  export type Array1<T> = readonly [T];
2
- type Index1 = 0;
2
+ export type Index1 = 0;
3
3
  export type Array2<T> = readonly [T, T];
4
- type Index2 = 0 | 1;
4
+ export type Tuple2<T0, T1> = readonly [T0, T1];
5
+ export type Index2 = 0 | 1;
5
6
  export type Array3<T> = readonly [T, T, T];
7
+ export type Tuple3<T0, T1, T2> = readonly [T0, T1, T2];
6
8
  export type Index3 = 0 | 1 | 2;
7
9
  export type Array4<T> = readonly [T, T, T, T];
8
- type Index4 = 0 | 1 | 2 | 3;
10
+ export type Index4 = 0 | 1 | 2 | 3;
9
11
  export type Array5<T> = readonly [T, T, T, T, T];
10
12
  export type Array8<T> = readonly [T, T, T, T, T, T, T, T];
11
13
  export type Array16<T> = readonly [T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T];
14
+ export type Index16 = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
15
+ export type Array1_5<T> = Array1<T> | Array2<T> | Array3<T> | Array4<T> | Array5<T>;
12
16
  export type Index5 = 0 | 1 | 2 | 3 | 4;
13
17
  export type KeyOf<T> = T extends Array1<infer _> ? Index1 : T extends Array2<infer _> ? Index2 : T extends Array3<infer _> ? Index3 : T extends Array4<infer _> ? Index4 : T extends Array5<infer _> ? Index5 : T extends readonly (infer _)[] ? number : never;
14
- export declare const at: (index: number) => <T>(a: readonly T[]) => T | null;
18
+ export declare const at: (i: number) => <T>(a: readonly T[]) => T | null;
15
19
  export declare const first: <T>(_: readonly T[]) => T | null;
16
- export declare const last: <T>(_: readonly T[]) => T | null;
17
- export declare const tail: <T>(_: readonly T[]) => readonly T[] | null;
20
+ export declare const last: <T>(a: readonly T[]) => T | null;
21
+ export declare const tail: <T>(a: readonly T[]) => readonly T[] | null;
18
22
  export declare const splitFirst: <T>(a: readonly T[]) => readonly [T, readonly T[]] | null;
19
- export declare const head: <T>(_: readonly T[]) => readonly T[] | null;
20
- export declare const splitLast: <T>(_: readonly T[]) => readonly [readonly T[], T] | null;
21
- export {};
23
+ export declare const head: <T>(a: readonly T[]) => readonly T[] | null;
24
+ export declare const splitLast: <T>(a: readonly T[]) => readonly [readonly T[], T] | null;
@@ -1,20 +1,19 @@
1
- import * as option from "../nullable/module.f.js";
2
- const { map } = option;
3
- const uncheckTail = a => a.slice(1);
4
- const uncheckHead = a => a.slice(0, -1);
5
- export const at = i => a => {
1
+ import { map } from "../nullable/module.f.js";
2
+ const uncheckTail = (a) => a.slice(1);
3
+ const uncheckHead = (a) => a.slice(0, -1);
4
+ export const at = (i) => (a) => {
6
5
  const r = a[i];
7
- return r === void 0 ? null : r;
6
+ return r === undefined ? null : r;
8
7
  };
9
8
  export const first = at(0);
10
- export const last = a => at(a.length - 1)(a);
11
- export const tail = a => a.length === 0 ? null : uncheckTail(a);
9
+ export const last = (a) => at(a.length - 1)(a);
10
+ export const tail = (a) => a.length === 0 ? null : uncheckTail(a);
12
11
  export const splitFirst = (a) => {
13
- const split = first => [first, uncheckTail(a)];
12
+ const split = (first) => [first, uncheckTail(a)];
14
13
  return map(split)(first(a));
15
14
  };
16
- export const head = a => a.length === 0 ? null : uncheckHead(a);
17
- export const splitLast = a => {
15
+ export const head = (a) => a.length === 0 ? null : uncheckHead(a);
16
+ export const splitLast = (a) => {
18
17
  const lastA = last(a);
19
18
  if (lastA === null) {
20
19
  return null;
@@ -6,5 +6,6 @@ declare const _default: {
6
6
  head: (() => void)[];
7
7
  tail: (() => void)[];
8
8
  splitFirst: (() => void)[];
9
+ splitLast: (() => void)[];
9
10
  };
10
11
  export default _default;
@@ -1,7 +1,6 @@
1
- import * as _ from "./module.f.js";
1
+ import { at, first, last, head, tail, splitFirst, splitLast } from "./module.f.js";
2
2
  import * as json from "../../json/module.f.js";
3
- import * as o from "../object/module.f.js";
4
- const { sort } = o;
3
+ import { sort } from "../object/module.f.js";
5
4
  const stringify = json.stringify(sort);
6
5
  export default {
7
6
  stringify: () => {
@@ -12,13 +11,13 @@ export default {
12
11
  },
13
12
  at: [
14
13
  () => {
15
- const result = _.at(2)([1, 20, 300]);
14
+ const result = at(2)([1, 20, 300]);
16
15
  if (result !== 300) {
17
16
  throw result;
18
17
  }
19
18
  },
20
19
  () => {
21
- const result = _.at(3)([1, 20, 300]);
20
+ const result = at(3)([1, 20, 300]);
22
21
  if (result !== null) {
23
22
  throw result;
24
23
  }
@@ -26,13 +25,13 @@ export default {
26
25
  ],
27
26
  first: [
28
27
  () => {
29
- const result = _.first([1, 20, 300]);
28
+ const result = first([1, 20, 300]);
30
29
  if (result !== 1) {
31
30
  throw result;
32
31
  }
33
32
  },
34
33
  () => {
35
- const result = _.first([]);
34
+ const result = first([]);
36
35
  if (result !== null) {
37
36
  throw result;
38
37
  }
@@ -40,13 +39,13 @@ export default {
40
39
  ],
41
40
  last: [
42
41
  () => {
43
- const result = _.last([1, 20, 300]);
42
+ const result = last([1, 20, 300]);
44
43
  if (result !== 300) {
45
44
  throw result;
46
45
  }
47
46
  },
48
47
  () => {
49
- const result = _.last([]);
48
+ const result = last([]);
50
49
  if (result !== null) {
51
50
  throw result;
52
51
  }
@@ -54,7 +53,7 @@ export default {
54
53
  ],
55
54
  head: [
56
55
  () => {
57
- const result = _.head([1, 20, 300]);
56
+ const result = head([1, 20, 300]);
58
57
  if (result === null) {
59
58
  throw result;
60
59
  }
@@ -64,7 +63,7 @@ export default {
64
63
  }
65
64
  },
66
65
  () => {
67
- const result = _.head([]);
66
+ const result = head([]);
68
67
  if (result !== null) {
69
68
  throw result;
70
69
  }
@@ -72,14 +71,14 @@ export default {
72
71
  ],
73
72
  tail: [
74
73
  () => {
75
- const result = _.tail([1, 20, 300]);
74
+ const result = tail([1, 20, 300]);
76
75
  const str = stringify(result);
77
76
  if (str !== '[20,300]') {
78
77
  throw str;
79
78
  }
80
79
  },
81
80
  () => {
82
- const result = _.tail([]);
81
+ const result = tail([]);
83
82
  if (result !== null) {
84
83
  throw result;
85
84
  }
@@ -87,27 +86,29 @@ export default {
87
86
  ],
88
87
  splitFirst: [
89
88
  () => {
90
- const result = _.splitFirst([1, 20, 300]);
89
+ const result = splitFirst([1, 20, 300]);
91
90
  const str = stringify(result);
92
91
  if (str !== '[1,[20,300]]') {
93
92
  throw str;
94
93
  }
95
94
  },
96
95
  () => {
97
- const result = _.splitFirst([]);
96
+ const result = splitFirst([]);
98
97
  if (result !== null) {
99
98
  throw result;
100
99
  }
101
100
  },
101
+ ],
102
+ splitLast: [
102
103
  () => {
103
- const result = _.splitLast([1, 20, 300]);
104
+ const result = splitLast([1, 20, 300]);
104
105
  const str = stringify(result);
105
106
  if (str !== '[[1,20],300]') {
106
107
  throw str;
107
108
  }
108
109
  },
109
110
  () => {
110
- const result = _.splitLast([]);
111
+ const result = splitLast([]);
111
112
  if (result !== null) {
112
113
  throw result;
113
114
  }
@@ -1,3 +1,3 @@
1
1
  export type BigFloat = readonly [bigint, number];
2
- export declare const multiply: (b: BigFloat) => (mul: bigint) => BigFloat;
2
+ export declare const multiply: ([m, e]: BigFloat) => (mul: bigint) => BigFloat;
3
3
  export declare const decToBin: (dec: BigFloat) => BigFloat;
@@ -1,8 +1,7 @@
1
- import * as bi from "../bigint/module.f.js";
2
- const { abs, sign } = bi;
1
+ import { abs, sign } from "../bigint/module.f.js";
3
2
  const twoPow53 = 9007199254740992n;
4
3
  const twoPow54 = 18014398509481984n;
5
- const increaseMantissa = ([m, e]) => min => {
4
+ const increaseMantissa = ([m, e]) => (min) => {
6
5
  if (m === 0n) {
7
6
  return [m, e];
8
7
  }
@@ -16,7 +15,7 @@ const increaseMantissa = ([m, e]) => min => {
16
15
  e--;
17
16
  }
18
17
  };
19
- const decreaseMantissa = ([m, e]) => max => {
18
+ const decreaseMantissa = ([m, e]) => (max) => {
20
19
  if (m === 0n) {
21
20
  return [m, e];
22
21
  }
@@ -30,10 +29,10 @@ const decreaseMantissa = ([m, e]) => max => {
30
29
  e++;
31
30
  }
32
31
  };
33
- const pow = base => exp => base ** BigInt(exp);
32
+ const pow = (base) => (exp) => base ** BigInt(exp);
34
33
  const pow5 = pow(5n);
35
- export const multiply = ([m, e]) => mul => [m * mul, e];
36
- const divide = ([m, e]) => div => [[m / div, e], m % div];
34
+ export const multiply = ([m, e]) => (mul) => [m * mul, e];
35
+ const divide = ([m, e]) => (div) => [[m / div, e], m % div];
37
36
  const round53 = ([[m, e], r]) => {
38
37
  const mabs = abs(m);
39
38
  const s = BigInt(sign(m));
@@ -1,5 +1,4 @@
1
- import * as _ from "./module.f.js";
2
- const { decToBin } = _;
1
+ import { decToBin } from "./module.f.js";
3
2
  export default {
4
3
  decToBin: [
5
4
  () => {
@@ -1,16 +1,13 @@
1
1
  import * as compare from '../function/compare/module.f.ts';
2
- import * as Operator from '../function/operator/module.f.ts';
2
+ import type * as Operator from '../function/operator/module.f.ts';
3
3
  import { type List } from '../list/module.f.ts';
4
- export declare const addition: (a: bigint) => (b: bigint) => bigint;
4
+ type Unary = Operator.Unary<bigint, bigint>;
5
+ type Reduce = Operator.Reduce<bigint>;
6
+ export declare const addition: Reduce;
5
7
  export declare const sum: (input: List<bigint>) => bigint;
6
- export declare const abs: (a: bigint) => bigint;
8
+ export declare const abs: Unary;
7
9
  export declare const sign: (a: bigint) => compare.Sign;
8
10
  export declare const serialize: (a: bigint) => string;
9
- type Additive<T> = {
10
- readonly 0: T;
11
- readonly add: Operator.Reduce<T>;
12
- };
13
- export declare const scalar_mul: <T>(a: Additive<T>) => (a: T) => (n: bigint) => T;
14
11
  /**
15
12
  * Calculates the base-2 logarithm (floor).
16
13
  *
@@ -1,5 +1,4 @@
1
1
  import * as compare from "../function/compare/module.f.js";
2
- import * as Operator from "../function/operator/module.f.js";
3
2
  const { unsafeCmp } = compare;
4
3
  import { reduce } from "../list/module.f.js";
5
4
  export const addition = a => b => a + b;
@@ -7,21 +6,6 @@ export const sum = reduce(addition)(0n);
7
6
  export const abs = a => a >= 0 ? a : -a;
8
7
  export const sign = a => unsafeCmp(a)(0n);
9
8
  export const serialize = a => `${a}n`;
10
- export const scalar_mul = ({ 0: _0, add }) => a => n => {
11
- let ai = a;
12
- let ni = n;
13
- let result = _0;
14
- while (true) {
15
- if ((ni & 1n) === 1n) {
16
- result = add(result)(ai);
17
- }
18
- ni >>= 1n;
19
- if (ni === 0n) {
20
- return result;
21
- }
22
- ai = add(ai)(ai);
23
- }
24
- };
25
9
  /**
26
10
  * Calculates the base-2 logarithm (floor).
27
11
  *
@@ -0,0 +1,73 @@
1
+ import type { Reduce } from "../function/operator/module.f.ts";
2
+ /**
3
+ * Represents a monoid, an algebraic structure with a binary operation
4
+ * and an identity (neutral) element.
5
+ *
6
+ * A monoid satisfies the following properties:
7
+ * 1. **Associativity**: The operation must be associative.
8
+ * For all `a`, `b`, and `c` in the set, `(a operation b) operation c = a operation (b operation c)`.
9
+ * {@link https://en.wikipedia.org/wiki/Associative_property Learn more about associativity}.
10
+ * 2. **Identity Element**: There exists an element (called the identity) such that,
11
+ * when combined with any other element under the operation, it leaves the other element unchanged.
12
+ * {@link https://en.wikipedia.org/wiki/Identity_element Learn more about identity elements}.
13
+ *
14
+ * Learn more about monoids: {@link https://en.wikipedia.org/wiki/Monoid}.
15
+ *
16
+ * @template T The type of the elements in the monoid.
17
+ */
18
+ export type Monoid<T> = {
19
+ /**
20
+ * The identity (neutral) element for the monoid.
21
+ * When combined with any value under the `operation`, it leaves the other value unchanged.
22
+ *
23
+ * Examples:
24
+ * - `0` for addition
25
+ * - `1` for multiplication
26
+ * - `""` for string concatenation
27
+ * - `[]` for array concatenation
28
+ *
29
+ * Learn more: {@link https://en.wikipedia.org/wiki/Identity_element}
30
+ */
31
+ readonly identity: T;
32
+ /**
33
+ * The associative binary operation of the monoid.
34
+ * Takes one value of type `T` and returns a function that takes another value of type `T`,
35
+ * producing a result of type `T`.
36
+ *
37
+ * Examples:
38
+ * - `(a, b) => a + b` for addition
39
+ * - `(a, b) => a * b` for multiplication
40
+ * - `(a, b) => a.concat(b)` for arrays or strings
41
+ *
42
+ * Learn more: {@link https://en.wikipedia.org/wiki/Binary_operation}
43
+ */
44
+ readonly operation: Reduce<T>;
45
+ };
46
+ /**
47
+ * Repeats a monoid operation `n` times on the given element `a`.
48
+ * This function efficiently performs the operation using exponentiation by squaring.
49
+ *
50
+ * @template T The type of the elements in the monoid.
51
+ * @param monoid The monoid structure, including the identity and binary operation.
52
+ * @returns A function that takes an element `a` and a repetition count `n`,
53
+ * and returns the result of applying the operation `n` times.
54
+ *
55
+ * @example
56
+ *
57
+ * ```ts
58
+ * const add: Monoid<number> = {
59
+ * identity: 0,
60
+ * operation: a => b => a + b,
61
+ * };
62
+ *
63
+ * const resultAdd = repeat(add)(2)(10n) // 20
64
+ *
65
+ * const concat: Monoid<string> = {
66
+ * identity: '',
67
+ * operation: a => b => a + b,
68
+ * };
69
+ *
70
+ * const resultConcat = repeat(concat)('ha')(3n) // 'hahaha'
71
+ * ```
72
+ */
73
+ export declare const repeat: <T>({ identity, operation }: Monoid<T>) => (a: T) => (n: bigint) => T;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Repeats a monoid operation `n` times on the given element `a`.
3
+ * This function efficiently performs the operation using exponentiation by squaring.
4
+ *
5
+ * @template T The type of the elements in the monoid.
6
+ * @param monoid The monoid structure, including the identity and binary operation.
7
+ * @returns A function that takes an element `a` and a repetition count `n`,
8
+ * and returns the result of applying the operation `n` times.
9
+ *
10
+ * @example
11
+ *
12
+ * ```ts
13
+ * const add: Monoid<number> = {
14
+ * identity: 0,
15
+ * operation: a => b => a + b,
16
+ * };
17
+ *
18
+ * const resultAdd = repeat(add)(2)(10n) // 20
19
+ *
20
+ * const concat: Monoid<string> = {
21
+ * identity: '',
22
+ * operation: a => b => a + b,
23
+ * };
24
+ *
25
+ * const resultConcat = repeat(concat)('ha')(3n) // 'hahaha'
26
+ * ```
27
+ */
28
+ export const repeat = ({ identity, operation }) => (a) => (n) => {
29
+ let ai = a;
30
+ let ni = n;
31
+ let result = identity;
32
+ while (true) {
33
+ if ((ni & 1n) !== 0n) {
34
+ result = operation(result)(ai);
35
+ }
36
+ ni >>= 1n;
37
+ if (ni === 0n) {
38
+ return result;
39
+ }
40
+ ai = operation(ai)(ai);
41
+ }
42
+ };
@@ -0,0 +1,5 @@
1
+ declare const _default: {
2
+ numberAdd: () => void;
3
+ stringConcat: () => void;
4
+ };
5
+ export default _default;
@@ -0,0 +1,27 @@
1
+ import { repeat } from "./module.f.js";
2
+ export default {
3
+ numberAdd: () => {
4
+ const add = {
5
+ identity: 0,
6
+ operation: a => b => a + b,
7
+ };
8
+ const resultAdd = repeat(add)(2)(10n); // 20
9
+ if (resultAdd !== 20) {
10
+ throw resultAdd;
11
+ }
12
+ const id = repeat(add)(42)(0n);
13
+ if (id !== 0) {
14
+ throw id;
15
+ }
16
+ },
17
+ stringConcat: () => {
18
+ const concat = {
19
+ identity: '',
20
+ operation: a => b => a + b,
21
+ };
22
+ const resultConcat = repeat(concat)('ha')(3n); // 'hahaha'
23
+ if (resultConcat !== 'hahaha') {
24
+ throw resultConcat;
25
+ }
26
+ }
27
+ };