functionalscript 0.0.305 → 0.0.309

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.
package/README.md CHANGED
@@ -19,3 +19,11 @@ In FunctionalScript:
19
19
  - Code should not have [side-effects](https://en.wikipedia.org/wiki/Side_effect_(computer_science)). Any JavaScript statement, expression, or function which has a side effect is not allowed in FunctionalScript. There are no exceptions to this rule, such as `unsafe` code which can be found in Rust, C#, and other languages.
20
20
  - A module can't depend on non FunctionalScript module.
21
21
  - It also has no standard library, only a safe subset of standard JavaScript API can be used without referencing other modules.
22
+
23
+ ## Applications
24
+
25
+ FunctionalScript code can be used
26
+
27
+ - in any JavaScript/TypeScript application,
28
+ - as a JSON with expressions,
29
+ - as a query language.
@@ -21,18 +21,18 @@ const split = path => path.split('/')
21
21
  /** @typedef {readonly[list.List<string>] | undefined} OptionList */
22
22
 
23
23
  /** @type {(s: OptionList) => (items: string) => OptionList} */
24
- const normItemsOp = prior => item => {
24
+ const normItemsOp = prior => first => {
25
25
  if (prior === undefined) { return undefined }
26
- const priorList = prior[0]
27
- switch (item) {
26
+ const tail = prior[0]
27
+ switch (first) {
28
28
  case '': case '.': { return prior }
29
29
  case '..': {
30
- const result = list.next(priorList)
30
+ const result = list.next(tail)
31
31
  if (result === undefined) { return undefined }
32
32
  return [result.tail]
33
33
  }
34
34
  default: {
35
- return [list.nonEmpty(item)(priorList)]
35
+ return [{ first, tail }]
36
36
  }
37
37
  }
38
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.305",
3
+ "version": "0.0.309",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test.js CHANGED
@@ -11,6 +11,7 @@ require('./commonjs/package/dependencies/test')
11
11
  require('./commonjs/package/test')
12
12
  require('./commonjs/path/test')
13
13
  require('./types/function/compare/test')
14
+ require('./types/stringSet/test')
14
15
 
15
16
  /** @type {() => never} */
16
17
  const assert = () => { throw 'assert' }
@@ -44,10 +44,8 @@ const array = require('../../array')
44
44
  */
45
45
 
46
46
  /** @type {<T>(item: PathItem<T>) => _.Node<T>} */
47
- const child = item => {
48
- /** @typedef {typeof item extends PathItem<infer T> ? T : never} T */
49
- return /** @type {_.Node<T>} */(item[1][item[0]])
50
- }
47
+ const child = item =>
48
+ /** @type {typeof item extends PathItem<infer T> ? _.Node<T> : never} */(item[1][item[0]])
51
49
 
52
50
  /**
53
51
  * @template T
@@ -98,6 +96,14 @@ const find = c => {
98
96
  return f(undefined)
99
97
  }
100
98
 
99
+ /** @type {<T>(first: First<T>) => boolean} */
100
+ const isFound = first => {
101
+ switch (first[0]) {
102
+ case 1: case 3: { return true }
103
+ default: { return false }
104
+ }
105
+ }
106
+
101
107
  /** @type {<T>(first: First<T>) => T | undefined} */
102
108
  const value = first => {
103
109
  switch (first[0]) {
@@ -123,4 +129,6 @@ module.exports = {
123
129
  find,
124
130
  /** @readonly */
125
131
  value,
126
- }
132
+ /** @readonly */
133
+ isFound,
134
+ }
@@ -1,4 +1,5 @@
1
1
  const seq = require('../list')
2
+ const option = require('../option')
2
3
 
3
4
  /**
4
5
  * @template T
@@ -48,24 +49,29 @@ const seq = require('../list')
48
49
  * @typedef { Leaf1<T> | Leaf2<T> | Branch3<T> | Branch5<T>} Node
49
50
  */
50
51
 
52
+ /**
53
+ * @template T
54
+ * @typedef {Node<T> | undefined} Tree
55
+ */
56
+
51
57
  /** @type {<T>(node: Node<T>) => seq.Thunk<T>} */
52
- const values = node => () => {
58
+ const nodeValues = node => () => {
53
59
  switch (node.length) {
54
60
  case 1: case 2: { return node }
55
61
  case 3: {
56
62
  return seq.flat([
57
- values(node[0]),
63
+ nodeValues(node[0]),
58
64
  [node[1]],
59
- values(node[2])
65
+ nodeValues(node[2])
60
66
  ])
61
67
  }
62
68
  default: {
63
69
  return seq.flat([
64
- values(node[0]),
70
+ nodeValues(node[0]),
65
71
  [node[1]],
66
- values(node[2]),
72
+ nodeValues(node[2]),
67
73
  [node[3]],
68
- values(node[4])
74
+ nodeValues(node[4])
69
75
  ])
70
76
  }
71
77
  }
@@ -81,6 +87,9 @@ const values = node => () => {
81
87
  * @typedef { readonly[...Branch5<T>, T, Node<T>] } Branch7
82
88
  */
83
89
 
90
+ /** @type {<T>(tree: Tree<T>) => seq.List<T>} */
91
+ const values = option.map(nodeValues)
92
+
84
93
  module.exports = {
85
94
  /** @readonly */
86
95
  values,
@@ -1,9 +1,9 @@
1
1
  const _ = require('..')
2
- const { todo } = require('../../../dev')
3
2
  const cmp = require('../../function/compare')
4
3
  const find = require('../find')
5
4
  const list = require('../../list')
6
5
  const array = require('../../array')
6
+ const option = require('../../option')
7
7
 
8
8
  /**
9
9
  * @template T
@@ -118,8 +118,8 @@ const reduce = list.reduce(reduceX([reduceValue0, reduceValue2]))
118
118
 
119
119
  const initReduce = reduceX([initValue0, initValue1])
120
120
 
121
- /** @type {<T>(c: cmp.Compare<T>) => (node: _.Node<T>) => undefined | _.Node<T>} */
122
- const remove = c => node => {
121
+ /** @type {<T>(c: cmp.Compare<T>) => (node: _.Node<T>) => _.Tree<T>} */
122
+ const nodeRemove = c => node => {
123
123
  /** @typedef {typeof c extends cmp.Compare<infer T> ? T : never} T */
124
124
  /** @type {() => undefined | RemovePath<T>} */
125
125
  const f = () => {
@@ -159,7 +159,12 @@ const remove = c => node => {
159
159
  return result.length === 1 ? result[0] : result
160
160
  }
161
161
 
162
+ /** @type {<T>(c: cmp.Compare<T>) => (tree: _.Tree<T>) => _.Tree<T>} */
163
+ const remove = c => option.map(nodeRemove(c))
164
+
162
165
  module.exports = {
166
+ /** @readonly */
167
+ nodeRemove,
163
168
  /** @readonly */
164
169
  remove,
165
- }
170
+ }
@@ -9,7 +9,7 @@ const { sort } = require('../../object')
9
9
  const set = node => value => s.set(stringCmp(value))(value)(node)
10
10
 
11
11
  /** @type {(node: btree.Node<string>) => (value: string) => btree.Node<string> | undefined} */
12
- const remove = node => value => _.remove(stringCmp(value))(node)
12
+ const remove = node => value => _.nodeRemove(stringCmp(value))(node)
13
13
 
14
14
  const jsonStr = json.stringify(sort)
15
15
 
@@ -36,7 +36,7 @@ const reduce = a => i => {
36
36
  }
37
37
 
38
38
  /** @type {<T>(c: cmp.Compare<T>) => (value: T) => (node: _.Node<T>) => _.Node<T>} */
39
- const set = c => value => node => {
39
+ const nodeSet = c => value => node => {
40
40
  const { first, tail } = find.find(c)(node)
41
41
  /** @typedef {typeof value} T */
42
42
  /** @type {() => Bracnh1To3<T>} */
@@ -87,7 +87,10 @@ const set = c => value => node => {
87
87
  return r.length === 1 ? r[0] : r
88
88
  }
89
89
 
90
+ /** @type {<T>(c: cmp.Compare<T>) => (value: T) => (tree: _.Tree<T>) => _.Node<T>} */
91
+ const set = c => value => tree => tree === undefined ? [value] : nodeSet(c)(value)(tree)
92
+
90
93
  module.exports = {
91
94
  /** @readonly */
92
95
  set,
93
- }
96
+ }
@@ -1,22 +1,27 @@
1
- /**
1
+ /**
2
2
  * @template I
3
3
  * @template O
4
- * @typedef {(_: I) => O} Func
4
+ * @typedef {(_: I) => O} Func
5
5
  */
6
6
 
7
- /**
7
+ /**
8
8
  * Postfix Compose function.
9
9
  *
10
- * @type {<I, X>(g: Func<I, X>) => <O>(f: Func<X, O>) => Func<I, O>}
10
+ * @type {<I, X>(g: Func<I, X>) => <O>(f: Func<X, O>) => Func<I, O>}
11
11
  */
12
12
  const compose = g => f => x => f(g(x))
13
13
 
14
14
  /** @type {<T>(value: T) => T} */
15
15
  const identity = value => value
16
16
 
17
+ /** @type {<A, B, C>(f: (a: A) => (b: B) => C) => (b: B) => (a: A) => C} */
18
+ const flip = f => b => a => f(a)(b)
19
+
17
20
  module.exports = {
18
21
  /** @readonly */
19
22
  identity,
20
23
  /** @readonly */
21
24
  compose,
25
+ /** @reeadonly */
26
+ flip,
22
27
  }
@@ -13,6 +13,9 @@
13
13
  /** @type {(separator: string) => Fold<string>} */
14
14
  const join = separator => prior => value => `${prior}${separator}${value}`
15
15
 
16
+ /** @type {Fold<string>} */
17
+ const concat = a => b => `${a}${b}`
18
+
16
19
  /** @type {Fold<number>} */
17
20
  const addition = a => b => a + b
18
21
 
@@ -26,8 +29,8 @@ const addition = a => b => a + b
26
29
  const logicalNot = v => !v
27
30
 
28
31
  /**
29
- * @template T
30
- * @typedef {Binary<T, T, boolean>} Equal
32
+ * @template T
33
+ * @typedef {Binary<T, T, boolean>} Equal
31
34
  */
32
35
 
33
36
  /** @type {<T>(a: T) => (b: T) => boolean} */
@@ -93,4 +96,6 @@ module.exports = {
93
96
  foldToScan,
94
97
  /** @readonly */
95
98
  counter,
99
+ /** @readonly */
100
+ concat,
96
101
  }
@@ -44,14 +44,13 @@ const { logicalNot, strictEqual, stateScanToScan, reduceToScan, foldToScan } = r
44
44
  * }} Concat
45
45
  */
46
46
 
47
- /** @type {<T>(first: T) => (tail: List<T>) => NonEmpty<T>} */
48
- const nonEmpty = first => tail => ({ first, tail })
49
-
50
- /** @type {(i: number) => <T>(array: readonly T[]) => Result<T>} */
51
- const fromArrayAt = i => array => i < array.length ? nonEmpty(array[i])(() => fromArrayAt(i + 1)(array)) : undefined
52
-
53
47
  /** @type {<T>(array: readonly T[]) => Result<T>} */
54
- const fromArray = fromArrayAt(0)
48
+ const fromArray = array => {
49
+ /** @typedef {typeof array extends readonly (infer T)[] ? T : never} T */
50
+ /** @type {(i: number) => Result<T>} */
51
+ const at = i => i < array.length ? { first: array[i], tail: () => at(i + 1) } : undefined
52
+ return at(0)
53
+ }
55
54
 
56
55
  /** @type {<T>(a: List<T>) => (b: List<T>) => List<T>} */
57
56
  const concat = a => b => b === undefined ? a : ({ isConcat: true, a, b })
@@ -78,7 +77,7 @@ const next = list => {
78
77
  }
79
78
 
80
79
  if (a !== undefined) {
81
- return nonEmpty(a.first)(concat(a.tail)(b))
80
+ return { first: a.first, tail: concat(a.tail)(b) }
82
81
  }
83
82
 
84
83
  if (b === undefined) { return undefined }
@@ -120,7 +119,7 @@ const flatStep = n => concat(n.first)(flat(n.tail))
120
119
  const flat = apply(flatStep)
121
120
 
122
121
  /** @type {<I, O>(f: (value: I) => O) => (n: NonEmpty<I>) => List<O>} */
123
- const mapStep = f => n => nonEmpty(f(n.first))(map(f)(n.tail))
122
+ const mapStep = f => n => ({ first: f(n.first), tail: map(f)(n.tail) })
124
123
 
125
124
  /** @type {<I, O>(f: (value: I) => O) => (input: List<I>) => List<O>} */
126
125
  const map = f => apply(mapStep(f))
@@ -131,7 +130,7 @@ const flatMap = f => compose(map(f))(flat)
131
130
  /** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
132
131
  const filterStep = f => n => {
133
132
  const tail = filter(f)(n.tail)
134
- return f(n.first) ? nonEmpty(n.first)(tail) : tail
133
+ return f(n.first) ? { first: n.first, tail } : tail
135
134
  }
136
135
 
137
136
  /** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
@@ -140,20 +139,20 @@ const filter = f => apply(filterStep(f))
140
139
  /** @type {<I, O>(f: (value: I) => O|undefined) => (n: NonEmpty<I>) => List<O>} */
141
140
  const filterMapStep = f => n => {
142
141
  const [first, tail] = [f(n.first), filterMap(f)(n.tail)]
143
- return first === undefined ? tail : nonEmpty(first)(tail)
142
+ return first === undefined ? tail : { first, tail }
144
143
  }
145
144
 
146
145
  /** @type {<I, O>(f: (value: I) => O|undefined) => (input: List<I>) => List<O>} */
147
146
  const filterMap = f => apply(filterMapStep(f))
148
147
 
149
148
  /** @type {<T>(f: (value: T) => boolean) => (n: NonEmpty<T>) => List<T>} */
150
- const takeWhileStep = f => n => f(n.first) ? nonEmpty(n.first)(takeWhile(f)(n.tail)) : undefined
149
+ const takeWhileStep = f => n => f(n.first) ? { first: n.first, tail: takeWhile(f)(n.tail) } : undefined
151
150
 
152
151
  /** @type {<T>(f: (value: T) => boolean) => (input: List<T>) => List<T>} */
153
152
  const takeWhile = f => apply(takeWhileStep(f))
154
153
 
155
154
  /** @type {(n: number) => <T>(result: NonEmpty<T>) => List<T>} */
156
- const takeStep = n => ne => 0 < n ? nonEmpty(ne.first)(take(n - 1)(ne.tail)) : undefined
155
+ const takeStep = n => ne => 0 < n ? { first: ne.first, tail: take(n - 1)(ne.tail) } : undefined
157
156
 
158
157
  /** @type {(n: number) => <T>(input: List<T>) => List<T>} */
159
158
  const take = n => apply(takeStep(n))
@@ -177,10 +176,11 @@ const first = def => input => {
177
176
  return result.first
178
177
  }
179
178
 
180
- /** @type {<D>(def: D) => <T>(input: List<T>) => D|T} */
181
- const last = def => input => {
182
- /** @typedef {typeof input extends List<infer T> ? T : never} T */
183
- let i = nonEmpty(/** @type {(typeof def)|T} */(def))(input)
179
+ /** @type {<D>(first: D) => <T>(tail: List<T>) => D|T} */
180
+ const last = first => tail => {
181
+ /** @typedef {typeof tail extends List<infer T> ? T : never} T */
182
+ /** @type {NonEmpty<typeof first|T>} */
183
+ let i = { first, tail }
184
184
  while (true) {
185
185
  const result = next(i.tail)
186
186
  if (result === undefined) {
@@ -212,19 +212,19 @@ const includes = value => input => some(map(strictEqual(value))(input))
212
212
  const countdown = count => () => {
213
213
  if (count <= 0) { return undefined }
214
214
  const first = count - 1
215
- return nonEmpty(first)(countdown(first))
215
+ return { first, tail: countdown(first) }
216
216
  }
217
217
 
218
218
  /** @type {<T>(list: List<T>) => List<T>} */
219
219
  const cycle = list => () => {
220
220
  const i = next(list)
221
- return i === undefined ? undefined : nonEmpty(i.first)(concat(i.tail)(cycle(list)))
221
+ return i === undefined ? undefined : { first: i.first, tail: concat(i.tail)(cycle(list)) }
222
222
  }
223
223
 
224
224
  /** @type {<I, O>(op: operator.Scan<I, O>) => (ne: NonEmpty<I>) => List<O>} */
225
225
  const scanStep = op => ne => {
226
- const [o, newOp] = op(ne.first)
227
- return nonEmpty(o)(scan(newOp)(ne.tail))
226
+ const [first, newOp] = op(ne.first)
227
+ return { first, tail: scan(newOp)(ne.tail) }
228
228
  }
229
229
 
230
230
  /** @type {<I, O>(op: operator.Scan<I, O>) => (input: List<I>) => List<O>} */
@@ -263,13 +263,13 @@ const length = reduce(operator.counter)(0)
263
263
  const entryOperator = index => value => [[index, value], index + 1]
264
264
 
265
265
  /** @type {<T>(input: List<T>) => List<Entry<T>>} */
266
- const entries = (input) => {
266
+ const entries = input => {
267
267
  /** @typedef {typeof input extends List<infer T> ? T : never} T */
268
268
  return stateScan(/** @type {operator.StateScan<T, Number, Entry<T>>} */(entryOperator))(0)(input)
269
269
  }
270
270
 
271
271
  /** @type {<T>(prior: List<T>) => (value: T) => List<T>} */
272
- const reverseOperator = prior => value => nonEmpty(value)(prior)
272
+ const reverseOperator = tail => first => ({ first, tail })
273
273
 
274
274
  /** @type {<T>(input: List<T>) => List<T>} */
275
275
  const reverse = reduce(reverseOperator)(undefined)
@@ -283,26 +283,36 @@ const zip = a => b => () => {
283
283
  if (aResult === undefined) { return undefined }
284
284
  const bResult = next(b)
285
285
  if (bResult === undefined) { return undefined }
286
- return nonEmpty(tuple2(aResult.first)(bResult.first))(zip(aResult.tail)(bResult.tail))
286
+ return { first: tuple2(aResult.first)(bResult.first), tail: zip(aResult.tail)(bResult.tail) }
287
287
  }
288
288
 
289
289
  /** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => List<boolean>} */
290
290
  const equalZip = e => a => b => () => {
291
291
  const [aResult, bResult] = [next(a), next(b)]
292
292
  return aResult === undefined || bResult === undefined
293
- ? nonEmpty(aResult === bResult)(undefined)
294
- : nonEmpty(e(aResult.first)(bResult.first))(equalZip(e)(aResult.tail)(bResult.tail))
293
+ ? { first: aResult === bResult, tail: undefined }
294
+ : { first: e(aResult.first)(bResult.first), tail: equalZip(e)(aResult.tail)(bResult.tail) }
295
295
  }
296
296
 
297
297
  /** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => boolean} */
298
298
  const equal = e => a => b => every(equalZip(e)(a)(b))
299
299
 
300
+ /** @type {(s: string) => List<number>} */
301
+ const toCharCodes = s => {
302
+ /** @type {(i: number) => Result<number>} */
303
+ const at = i => {
304
+ const first = s.charCodeAt(i)
305
+ return isNaN(first) ? undefined : { first, tail: () => at(i + 1) }
306
+ }
307
+ return at(0)
308
+ }
309
+
310
+ const fromCharCodes = compose(map(String.fromCharCode))(fold(operator.concat)(''))
311
+
300
312
  module.exports = {
301
313
  /** @readonly */
302
314
  empty: undefined,
303
315
  /** @readonly */
304
- nonEmpty,
305
- /** @readonly */
306
316
  concat,
307
317
  /** @readonly */
308
318
  next,
@@ -374,4 +384,8 @@ module.exports = {
374
384
  zip,
375
385
  /** @readonly */
376
386
  equal,
387
+ /** @readonly */
388
+ toCharCodes,
389
+ /** @readonly */
390
+ fromCharCodes,
377
391
  }
@@ -234,6 +234,12 @@ const stringify = sequence => json.stringify(sort)(_.toArray(sequence))
234
234
  if (result !== false) { throw result }
235
235
  }
236
236
 
237
+ {
238
+ const r = _.toCharCodes("Hello world!")
239
+ const x = _.fromCharCodes(r)
240
+ if (x !== "Hello world!") { throw x }
241
+ }
242
+
237
243
  // stress tests
238
244
 
239
245
  const stress = () => {
@@ -1,24 +1,15 @@
1
- const option = require("../option")
2
1
  const btree = require('../btree')
3
2
  const { values } = require("../btree")
4
3
  const find = require('../btree/find')
5
4
  const s = require('../btree/set')
6
- const compare = require("../function/compare")
7
- const { stringCmp } = require("../function/compare")
8
- const list = require("../list")
5
+ const compare = require('../function/compare')
6
+ const { stringCmp } = require('../function/compare')
7
+ const list = require('../list')
8
+ const btRemove = require('../btree/remove')
9
+ const { flip } = require('../function')
9
10
 
10
11
  /** @typedef {compare.Sign} Sign */
11
12
 
12
- /**
13
- * @template T
14
- * @typedef {btree.Leaf1<T>} Leaf1
15
- */
16
-
17
- /**
18
- * @template T
19
- * @typedef {btree.Node<T>} TNode
20
- */
21
-
22
13
  /**
23
14
  * @template T
24
15
  * @typedef {compare.Compare<T>} Cmp
@@ -31,7 +22,7 @@ const list = require("../list")
31
22
 
32
23
  /**
33
24
  * @template T
34
- * @typedef {undefined|TNode<Entry<T>>} Map
25
+ * @typedef {btree.Tree<Entry<T>>} Map
35
26
  */
36
27
 
37
28
  /** @type {(a: string) => <T>(b: Entry<T>) => Sign} */
@@ -44,25 +35,20 @@ const at = name => map => {
44
35
  return result === undefined ? undefined : result[1]
45
36
  }
46
37
 
38
+ /** @type {<T>(entry: Entry<T>) => (map: Map<T>) => Map<T>} */
39
+ const setEntry = entry => s.set(keyCmp(entry[0]))(entry)
40
+
47
41
  /** @type {(name: string) => <T>(value: T) => (map: Map<T>) => Map<T>} */
48
- const set = name => value => map => {
49
- /** @type {Entry<typeof value>} */
50
- const entry = [name, value]
51
- if (map === undefined) { return [entry] }
52
- return s.set(keyCmp(name))(entry)(map)
53
- }
42
+ const set = name => value => setEntry([name, value])
54
43
 
55
44
  /** @type {<T>(map: Map<T>) => list.List<Entry<T>>} */
56
- const entries = map => map === undefined ? undefined : values(map)
57
-
58
- /** @type {<T>(map: Map<T>) => (entry: Entry<T>) => Map<T>} */
59
- const setOp = map => ([name, value]) => set(name)(value)(map)
45
+ const entries = values
60
46
 
61
47
  /** @type {<T>(entries: list.List<Entry<T>>) => Map<T>} */
62
- const fromEntries = entries => {
63
- /** @typedef {typeof entries extends list.List<Entry<infer T>> ? T : never} T */
64
- return list.reduce(setOp)(/** @type {Map<T>} */(undefined))(entries)
65
- }
48
+ const fromEntries = list.reduce(flip(setEntry))(undefined)
49
+
50
+ /** @type {(name: string) => <T>(map: Map<T>) => Map<T>} */
51
+ const remove = name => btRemove.remove(keyCmp(name))
66
52
 
67
53
  module.exports = {
68
54
  /** @readonly */
@@ -75,4 +61,6 @@ module.exports = {
75
61
  entries,
76
62
  /** @readonly */
77
63
  fromEntries,
64
+ /** @readonly */
65
+ remove,
78
66
  }
package/types/map/test.js CHANGED
@@ -1,4 +1,4 @@
1
- const { at, set, empty, entries } = require('.')
1
+ const { at, set, empty, entries, remove } = require('.')
2
2
  const seq = require('../list')
3
3
 
4
4
  {
@@ -38,6 +38,8 @@ const seq = require('../list')
38
38
  if (at('x')(m) !== undefined) { throw 'error' }
39
39
 
40
40
  // console.log(Array.from(m.entries()))
41
+ m = remove('Hello world!')(m)
42
+ if (at('Hello world!')(m) !== undefined) { throw m }
41
43
  }
42
44
 
43
45
  {
@@ -0,0 +1,36 @@
1
+ const btree = require('../btree')
2
+ const find = require('../btree/find')
3
+ const btSet = require('../btree/set')
4
+ const btRemove = require('../btree/remove')
5
+ const { stringCmp } = require("../function/compare")
6
+ const list = require('../list')
7
+ const { flip, compose } = require('../function')
8
+
9
+ /** @typedef {btree.Tree<string>} StringSet */
10
+
11
+ /** @type {(value: string) => (set: StringSet) => boolean} */
12
+ const contains = value => s => s !== undefined && find.isFound(find.find(stringCmp(value))(s).first)
13
+
14
+ /** @type {(value: string) => (s: StringSet) => StringSet} */
15
+ const set = value => btSet.set(stringCmp(value))(value)
16
+
17
+ /** @type {(s: StringSet) => list.List<string>} */
18
+ const values = btree.values
19
+
20
+ const fromValues = list.reduce(flip(set))(undefined)
21
+
22
+ /** @type {(value: string) => (s: StringSet) => StringSet} */
23
+ const remove = compose(stringCmp)(btRemove.remove)
24
+
25
+ module.exports = {
26
+ /** @readonly */
27
+ contains,
28
+ /** @readonly */
29
+ set,
30
+ /** @readonly */
31
+ values,
32
+ /** @readonly */
33
+ fromValues,
34
+ /** @readonly */
35
+ remove,
36
+ }
@@ -0,0 +1,33 @@
1
+ const _ = require('.')
2
+
3
+ {
4
+ const r = _.set('hello')(undefined)
5
+ if (!_.contains('hello')(r)) { throw r }
6
+ if (_.contains('hello1')(r)) { throw r }
7
+ }
8
+
9
+ {
10
+ let r = _.set('hello')(undefined)
11
+ r = _.set('world')(r)
12
+ r = _.set('HELLO')(r)
13
+ r = _.set('WORLD!')(r)
14
+ if (!_.contains('hello')(r)) { throw r }
15
+ if (_.contains('hello1')(r)) { throw r }
16
+ if (!_.contains('HELLO')(r)) { throw r }
17
+ if (_.contains('WORLD')(r)) { throw r }
18
+ if (!_.contains('world')(r)) { throw r }
19
+ if (_.contains('world!')(r)) { throw r }
20
+ if (!_.contains('WORLD!')(r)) { throw r }
21
+ //
22
+ r = _.remove('hello')(r)
23
+ if (_.contains('hello')(r)) { throw r }
24
+ if (!_.contains('world')(r)) { throw r }
25
+ r = _.remove('world')(r)
26
+ if (_.contains('world')(r)) { throw r }
27
+ if (!_.contains('HELLO')(r)) { throw r }
28
+ r = _.remove('HELLO')(r)
29
+ if (_.contains('HELLO')(r)) { throw r }
30
+ if (!_.contains('WORLD!')(r)) { throw r }
31
+ r = _.remove('WORLD!')(r)
32
+ if (r !== undefined) { throw r }
33
+ }