-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjsPreludeMenu.json
582 lines (582 loc) · 181 KB
/
jsPreludeMenu.json
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
{
"Endo": "// Endo :: (a -> a) -> Endo a\nconst Endo = f =>\n // An endofunction lifted into an Endo object.\n // A wrapper around an (a -> a) function, used as\n // the monoid of endomorphisms under composition.\n ({\n type: \"Endo\",\n appEndo: f\n });",
"Just": "// Just :: a -> Maybe a\nconst Just = x => ({\n type: \"Maybe\",\n Just: x\n});",
"Left": "// Left :: a -> Either a b\nconst Left = x => ({\n type: \"Either\",\n Left: x\n});",
"Node": "// Node :: a -> [Tree a] -> Tree a\nconst Node = v =>\n // Constructor for a Tree node which connects a\n // value of some kind to a list of zero or\n // more child trees.\n xs => ({\n type: \"Node\",\n root: v,\n nest: xs || []\n });",
"Nothing": "// Nothing :: Maybe a\nconst Nothing = () => ({\n type: \"Maybe\",\n Nothing: true\n});",
"Ratio": "// Ratio :: Integral a => a -> a -> Ratio a\nconst Ratio = a => b => {\n const go = (x, y) =>\n 0 !== y\n ? (() => {\n const d = gcd(x)(y);\n\n return {\n type: \"Ratio\",\n // numerator\n \"n\": Math.trunc(x / d),\n // denominator\n \"d\": Math.trunc(y / d)\n };\n })()\n : undefined;\n\n return go(a * signum(b), abs(b));\n};",
"Right": "// Right :: b -> Either a b\nconst Right = x => ({\n type: \"Either\",\n Right: x\n});",
"Tuple": "// Tuple (,) :: a -> b -> (a, b)\nconst Tuple = a =>\n // A pair of values, possibly of\n // different types.\n b => ({\n type: \"Tuple\",\n \"0\": a,\n \"1\": b,\n length: 2,\n *[Symbol.iterator]() {\n for (const k in this) {\n if (!isNaN(k)) {\n yield this[k];\n }\n }\n }\n });",
"Tuple3": "// Tuple3 (,,) :: a -> b -> c -> (a, b, c)\nconst Tuple3 = a => b => c => ({\n type: \"Tuple3\",\n \"0\": a,\n \"1\": b,\n \"2\": c,\n length: 3,\n *[Symbol.iterator]() {\n for (const k in this) {\n if (!isNaN(k)) {\n yield this[k];\n }\n }\n }\n});",
"TupleN": "// TupleN :: a -> b ... -> (a, b ... )\nconst TupleN = (...args) => {\n // A Tuple of an arbitrary number of items.\n const n = args.length;\n\n return {\n ...args.reduce(\n (a, x, i) => ({\n ...a,\n [i]: x\n }),\n {\n type: 2 !== n\n ? `Tuple${n}`\n : \"Tuple\",\n length: n,\n *[Symbol.iterator]() {\n for (const k in this) {\n if (!isNaN(k)) {\n yield this[k];\n }\n }\n }\n })\n };\n};",
"ZipList": "// ZipList :: a -> {getZipList :: [a]}\nconst ZipList = x => ({\n // Constructor for an applicative ZipList\n type: \"ZipList\",\n getZipList: x\n});",
"abs": "// abs :: Num -> Num\nconst abs = x =>\n // Absolute value of a given number\n // without the sign.\n 0 > x\n ? -x\n : x;",
"add": "// add (+) :: Num a => a -> a -> a\nconst add = a =>\n // Curried addition.\n b => a + b;",
"adjust": "// adjust :: (a -> a) -> Key ->\n// Dict Key a -> Dict Key a\nconst adjust = f =>\n // The orginal dictionary, unmodified, if k is\n // not an existing key.\n // Otherwise, a new copy in which the existing\n // value of k is updated by application of f.\n k => dict => k in dict\n ? {\n ...dict,\n [k]: f(dict[k])\n }\n : dict;",
"alert": "// alert :: String => String -> IO String\nconst alert = title =>\n // Display of a given title and message.\n s => {\n const sa = Object.assign(\n Application(\"System Events\"), {\n includeStandardAdditions: true\n });\n\n return (\n sa.activate(),\n sa.displayDialog(s, {\n withTitle: title,\n buttons: [\"OK\"],\n defaultButton: \"OK\"\n }),\n s\n );\n };",
"all": "// all :: (a -> Bool) -> [a] -> Bool\nconst all = p =>\n // True if p(x) holds for every x in xs.\n xs => [...xs].every(p);",
"allSame": "// allSame :: [a] -> Bool\nconst allSame = xs =>\n // True if xs has less than 2 items, or every item\n // in the tail of the list is identical to the head.\n 2 > xs.length || (() => {\n const [h, ...t] = xs;\n\n return t.every(x => h === x);\n })();",
"allTree": "// allTree :: (a -> Bool) -> Tree a -> Bool\nconst allTree = p =>\n // True if p holds for all nodes of the\n // tree to which allTree(p) is applied.\n foldTree(\n x => xs => p(x) && xs.every(Boolean)\n );",
"and": "// and :: [Bool] -> Bool\nconst and = xs =>\n // True unless any value in xs is false.\n [...xs].every(Boolean);",
"any": "// any :: (a -> Bool) -> [a] -> Bool\nconst any = p =>\n // True if p(x) holds for at least\n // one item in xs.\n xs => [...xs].some(p);",
"anyTree": "// anyTree :: (a -> Bool) -> Tree a -> Bool\nconst anyTree = p =>\n // True if p holds for any node of the\n // tree to which anyTree(p) is applied.\n foldTree(\n x => xs =>\n p(x) || xs.some(Boolean)\n );",
"ap": "// ap (<*>) :: Monad m => m (a -> b) -> m a -> m b\nconst ap = mf =>\n // Applies wrapped functions to wrapped values,\n // for example applying a list of functions to a list\n // of values or applying:\n // Just(f) to Just(x), Right(f) to Right(x),\n // f(x) to g(x) etc.\n mx => ({\n \"Either\": () => apLR,\n \"Maybe\": () => apMay,\n \"Node\": () => apTree,\n \"Tuple\": () => apTuple,\n \"List\": () => apList,\n \"(a -> b)\": () => apFn\n })[typeName(mx) || \"List\"]()(mf)(mx);",
"apFn": "// apFn :: (a -> b -> c) -> (a -> b) -> (a -> c)\nconst apFn = f =>\n // Applicative instance for functions.\n // f(x) applied to g(x).\n g => x => f(x)(\n g(x)\n );",
"apLR": "// apLR (<*>) :: Either e (a -> b) -> Either e a -> Either e b\nconst apLR = flr =>\n // Either a Left value, or the application of a\n // function in Either to a value in Either.\n liftA2LR(x => x)(flr);",
"apList": "// apList (<*>) :: [(a -> b)] -> [a] -> [b]\nconst apList = fs =>\n // The sequential application of each of a list\n // of functions to each of a list of values.\n // apList([x => 2 * x, x => 20 + x])([1, 2, 3])\n // -> [2, 4, 6, 21, 22, 23]\n xs => fs.flatMap(f => xs.map(f));",
"apMay": "// apMay (<*>) :: Maybe (a -> b) -> Maybe a -> Maybe b\nconst apMay = mf =>\n // Just an application of Maybe a function to\n // to Maybe a value, or Nothing.\n liftA2May(x => x)(mf);",
"apTree": "// apTree (<*>) :: Tree (a -> b) -> Tree a -> Tree b\nconst apTree = tf =>\n // A new tree derived by applying each of a tree\n // of functions to each node value in another tree.\n liftA2Tree(\n x => x\n )(tf);",
"apTuple": "// apTuple (<*>) :: Monoid m => (m, (a -> b)) -> (m, a) -> (m, b)\nconst apTuple = ab =>\n // A tuple obtained by applying the function in the second\n // value of ab to the second value in an existing tuple,\n // and concatenating the first values of each tuple.\n liftA2Tuple(x => x)(ab);",
"apZL": "// apZL (<*>) :: ZipList (a -> b) -> ZipList a -> ZipList b\n// The application of a function in one ZipList\n// to each value in another ZipList.\nconst apZL = zf =>\n liftA2ZL(x => x)(zf);",
"apZip": "// apZip :: [(a -> b)] -> [a] -> [b]\nconst apZip = fs =>\n // Zip applicative.\n // Each function in fs applied to the value\n // in the corresponding position in xs.\n xs => fs.slice(\n 0, Math.min(fs.length, xs.length)\n )\n .map((f, i) => f(xs[i]));",
"appEndo": "// appEndo :: Endo a -> (a -> a)\nconst appEndo = endo =>\n // Accessor for the function in an Endo type.\n endo.appEndo;",
"append": "// append (<>) :: [a] -> [a] -> [a]\nconst append = xs =>\n // Two lists joined into one.\n ys => xs.concat(ys);",
"appendFile": "// appendFile :: FilePath -> String -> IO Bool\nconst appendFile = fp =>\n // The file at fp updated with a new string\n // appended to its existing contents.\n txt => {\n const fpFull = filePath(fp);\n\n return doesFileExist(fpFull)\n ? (() => {\n const\n h = $.NSFileHandle\n .fileHandleForWritingAtPath(\n $(fpFull)\n );\n\n return (\n h.seekToEndOfFile,\n h.writeData(\n $(txt)\n .dataUsingEncoding(\n $.NSUTF8StringEncoding\n )\n ),\n h.closeFile,\n true\n );\n })()\n : doesDirectoryExist(takeDirectory(fpFull))\n ? (writeFile(fpFull)(txt), true)\n : false;\n };",
"appendFileMay": "// appendFileMay :: FilePath -> String -> Maybe IO FilePath\nconst appendFileMay = fp =>\n // Just the fully-expanded file path of\n // any file at found strPath, after it has been\n // updated by appending the given string, or\n // Nothing if no file is found at that path,\n // or the file is found but can not be updated.\n txt => {\n const fpFull = filePath(fp);\n\n return doesFileExist(fpFull)\n ? (() => {\n const\n h = $.NSFileHandle\n .fileHandleForWritingAtPath(\n $(fpFull)\n );\n\n return (\n h.seekToEndOfFile,\n h.writeData(\n $(txt)\n .dataUsingEncoding(\n $.NSUTF8StringEncoding\n )\n ),\n h.closeFile,\n Just(fpFull)\n );\n })()\n : doesDirectoryExist(takeDirectory(fpFull))\n ? (\n writeFile(fpFull)(txt),\n Just(fpFull)\n )\n : Nothing();\n };",
"appendGen": "// appendGen (++) :: Gen [a] -> Gen [a] -> Gen [a]\nconst appendGen = xs =>\n // A new generator composed from the\n // concatenation of two existing generators.\n function *(ys) {\n for (const vs of [xs, ys]) {\n let nxt = vs.next();\n\n while (!nxt.done) {\n yield nxt.value;\n nxt = vs.next();\n }\n }\n };",
"apply": "// apply ($) :: (a -> b) -> a -> b\nconst apply = f =>\n // Application operator.\n x => f(x);",
"applyN": "// applyN :: Int -> (a -> a) -> a -> a\nconst applyN = n =>\n // The value of n applications of f to x.\n // (Church numeral n)\n f => x => Array.from({\n length: n\n }, () => f)\n .reduce((a, g) => g(a), x);",
"approxRatio": "// approxRatio :: Real -> Real -> Ratio\nconst approxRatio = epsilon =>\n n => {\n const\n c = gcdApprox(\n Boolean(epsilon)\n ? epsilon\n : (1 / 10000)\n )(1, n);\n\n return Ratio(\n Math.floor(n / c)\n )(\n Math.floor(1 / c)\n );\n };",
"argvLength": "// argvLength :: Function -> Int\nconst argvLength = f =>\n // The number of arguments defined for the given function.\n f.length;",
"assocs": "// assocs :: Map k a -> [(k, a)]\nconst assocs = m =>\n // A list of (key, value) tuples derived from\n // the given dictionary.\n Object.entries(m).map(\n ([k, v]) => Tuple(k)(v)\n );",
"base64decode": "// base64decode :: String -> String\nconst base64decode = s =>\n // Base64 decoding of the given string.\n ObjC.unwrap(\n $.NSString.alloc.initWithDataEncoding(\n $.NSData.alloc.initWithBase64EncodedStringOptions(\n s, $.NSDataBase64DecodingIgnoreUnknownCharacters\n ),\n $.NSUTF8StringEncoding\n )\n );",
"base64encode": "// base64encode :: String -> String\nconst base64encode = s =>\n // Base64 encoding of the given string.\n ObjC.unwrap(\n $.NSString.stringWithString(s)\n .dataUsingEncoding(\n $.NSUTF8StringEncoding\n )\n .base64EncodedStringWithOptions(0)\n );",
"biList": "// biList :: (a, a) -> [a]\nconst biList = ab =>\n // A list of two items derived from a tuple.\n [...ab];",
"bimap": "// bimap :: (a -> b) -> (c -> d) -> (a, c) -> (b, d)\nconst bimap = f =>\n // Tuple instance of bimap.\n // A tuple of the application of f and g to the\n // first and second values respectively.\n g => tpl => Tuple(f(tpl[0]))(\n g(tpl[1])\n );",
"bimapLR": "// bimapLR :: (a -> b) -> (c -> d) -> ֵEither ֵֵa c -> Either b d\nconst bimapLR = f =>\n // Instance of bimap for Either values.\n // Either the application of f to a Left value,\n // or the application of g to a Right value.\n g => lr => lr.Left\n ? Left(f(lr.Left))\n : Right(g(lr.Right));",
"bimapN": "// bimapN :: (a -> b) -> (c -> d) -> TupleN -> TupleN\nconst bimapN = f =>\n // An n-tuple instance of bimap.\n // An n-tuple of unchanged dimension in which\n // the final value is an application of g\n // and the penultimate value is an application of f.\n g => nTuple => {\n const n = nTuple.length;\n\n return 1 < n\n ? TupleN(\n ...Array.from(nTuple).slice(0, n - 2),\n f(nTuple[n - 2]), g(nTuple[n - 1])\n )\n : null;\n };",
"bind": "// bind (>>=) :: Monad m => m a -> (a -> m b) -> m b\nconst bind = m =>\n // Two computations sequentially composed,\n // with any value produced by the first\n // passed as an argument to the second.\n mf => Array.isArray(m)\n ? bindList(m)(mf)\n : ({\n \"Either\": () => bindLR,\n \"Maybe\": () => bindMay,\n \"Tuple\": () => bindTuple,\n \"function\": () => bindFn\n })[m.type || typeof m]()(m)(mf);",
"bindFn": "// bindFn (>>=) :: (a -> b) -> (b -> a -> c) -> a -> c\nconst bindFn = f =>\n // Binary operator applied over f x and x.\n op => x => op(f(x))(x);",
"bindLR": "// bindLR (>>=) :: Either a ->\n// (a -> Either b) -> Either b\nconst bindLR = lr =>\n // Bind operator for the Either option type.\n // If lr has a Left value then lr unchanged,\n // otherwise the function mf applied to the\n // Right value in lr.\n mf => \"Left\" in lr\n ? lr\n : mf(lr.Right);",
"bindList": "// bindList (>>=) :: [a] -> (a -> [b]) -> [b]\nconst bindList = xs =>\n // The bind operator for Arrays.\n mf => [...xs].flatMap(mf);",
"bindMay": "// bindMay (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b\nconst bindMay = mb =>\n // Nothing if mb is Nothing, or the application of the\n // (a -> Maybe b) function mf to the contents of mb.\n mf => mb.Nothing\n ? mb\n : mf(mb.Just);",
"bindTuple": "// bindTuple (>>=) :: Monoid a => (a, a) -> (a -> (a, b)) -> (a, b)\nconst bindTuple = ([a, b]) =>\n // The bind operator for Tuples\n f => first(mappend(a))(\n f(b)\n );",
"bool": "// bool :: a -> a -> Bool -> a\nconst bool = f =>\n // t if p(x) else f.\n t => p => p ? t : f;",
"both": "// both :: (a -> b) -> (a, a) -> (b, b)\nconst both = f =>\n // A tuple obtained by separately\n // applying f to each of the two\n // values in the given tuple.\n ([a, b]) => Tuple(\n f(a)\n )(\n f(b)\n );",
"breakOn": "// breakOn :: Eq a => [a] -> [a] -> ([a], [a])\n// breakOn :: String -> String -> ([Char], [Char])\nconst breakOn = needle =>\n // A tuple of the prefix before the first match\n // and the whole remainder (including the match).\n haystack => {\n const ns = [...needle];\n\n const go = hs =>\n isPrefixOf(ns)(hs)\n ? Tuple([])(hs)\n : 0 === hs.length\n ? Tuple([])([])\n : first(\n v => [hs[0]].concat(v)\n )(\n go(hs.slice(1))\n );\n\n return go([...haystack]);\n };",
"breakOnAll": "// breakOnAll :: String -> String -> [(String, String)]\nconst breakOnAll = needle =>\n // Tuples breaking the string at\n // all non-overlapping instances\n // of the needle in the haystack.\n haystack => Boolean(needle)\n ? haystack.split(needle)\n .reduce((a, _, i, xs) =>\n 0 < i\n ? a.concat([\n Tuple(\n xs.slice(0, i).join(needle)\n )(\n needle + xs.slice(i)\n .join(needle)\n )\n ])\n : a, [])\n : null;",
"breakOnMay": "// breakOnMay :: String -> String -> Maybe (String, String)\nconst breakOnMay = needle =>\n // Maybe (prefix before match, match + rest)\n haystack => Boolean(needle)\n ? (() => {\n const xs = haystack.split(needle);\n\n return Just(Boolean(xs.length)\n ? Tuple(\n xs[0]\n )(\n haystack.slice(xs[0].length)\n )\n : Tuple(haystack)(\"\"));\n })()\n : Nothing();",
"break_": "// break_ :: (a -> Bool) -> [a] -> ([a], [a])\nconst break_ = p =>\n // The longest prefix of xs in which\n // all values return false for p,\n // tupled with the rest.\n xs => {\n const i = xs.findIndex(p);\n\n return -1 !== i\n ? Tuple(xs.slice(0, i))(\n xs.slice(i)\n )\n : Tuple(xs)([]);\n };",
"bulleted": "// bulleted :: String -> String -> String\nconst bulleted = strTab =>\n // A copy of s in which each line is\n // preceded by a whitespace indent,\n // followed by a hyphen and space.\n s => s.split(/[\\n\\r]+/u).map(\n x => \"\" !== x\n ? `${strTab}- ${x}`\n : x\n )\n .join(\"\\n\");",
"cartesianProduct": "// cartesianProduct :: [a] -> [b] -> [[a, b]]\nconst cartesianProduct = xs =>\n // Every tuple in the cartesian product\n // of xs and ys.\n ys => [...xs].flatMap(\n x => [...ys].flatMap(\n y => [Tuple(x)(y)]\n )\n );",
"caseOf": "// caseOf :: [(a -> Bool, b)] -> b -> a -> b\nconst caseOf = pvs =>\n // List of (Predicate, value) tuples ->\n // Default value -> Value to test -> Output value\n otherwise => x => {\n const mb = pvs.reduce(\n (a, pv) => a.Nothing\n ? pv[0](x)\n ? Just(pv[1])\n : a\n : a,\n Nothing()\n );\n\n return mb.Nothing\n ? otherwise\n : mb.Just;\n };",
"catMaybes": "// catMaybes :: [Maybe a] -> [a]\nconst catMaybes = mbs =>\n mbs.flatMap(\n m => m.Nothing\n ? []\n : [m.Just]\n );",
"ceiling": "// ceiling :: Num -> Int\nconst ceiling = x => {\n // The least integer not less than x.\n const\n nr = properFraction(x),\n n = nr[0];\n\n return 0 < nr[1]\n ? 1 + n\n : n;\n};",
"center": "// center :: Int -> Char -> String -> String\nconst center = n =>\n // Size of space -> filler Char ->\n // String -> Centered String\n c => s => {\n const gap = n - s.length;\n\n return 0 < gap\n ? (() => {\n const\n margin = c.repeat(Math.floor(gap / 2)),\n dust = c.repeat(gap % 2);\n\n return `${margin}${s}${margin}${dust}`;\n })()\n : s;\n };",
"chars": "// chars :: String -> [Char]\nconst chars = s =>\n [...s];",
"chop": "// chop :: ([a] -> (b, [a])) -> [a] -> [b]\nconst chop = f =>\n // A segmentation of xs by tail recursion with a\n // function which returns a (prefix, residue) tuple.\n xs => {\n const go = ys =>\n 0 < ys.length\n ? (() => {\n const [b, bs] = f(ys);\n\n return [b].concat(go(bs));\n })()\n : [];\n\n return go([...xs]);\n };",
"chr": "// chr :: Int -> Char\nconst chr = x =>\n // The character at unix code-point x.\n String.fromCodePoint(x);",
"chunksOf": "// chunksOf :: Int -> [a] -> [[a]]\nconst chunksOf = n => {\n // xs split into sublists of length n.\n // The last sublist will be short if n\n // does not evenly divide the length of xs .\n const go = xs => {\n const chunk = xs.slice(0, n);\n\n return 0 < chunk.length\n ? [chunk, ...go(xs.slice(n))]\n : [];\n };\n\n return go;\n};",
"combinations": "// combinations :: Int -> [a] -> [[a]]\nconst combinations = n =>\n // All combinations, without repetition,\n // of n items drawn from xs.\n xs => {\n const go = (m, ys) =>\n 1 > m\n ? [[]]\n : 0 === ys.length\n ? []\n : (\n (h, rest) => [\n ...go(m - 1, rest)\n .map(t => [h, ...t]),\n ...go(m, rest)\n ]\n )(\n ys[0], ys.slice(1)\n );\n\n return (go)(n, xs);\n };",
"combine": "// combine (</>) :: FilePath -> FilePath -> FilePath\nconst combine = fp =>\n // The concatenation of two filePath segments,\n // without omission or duplication of \"/\".\n fp1 => Boolean(fp) && Boolean(fp1)\n ? \"/\" === fp1.slice(0, 1)\n ? fp1\n : \"/\" === fp.slice(-1)\n ? fp + fp1\n : `${fp}/${fp1}`\n : (fp + fp1);",
"compare": "// compare :: a -> a -> Ordering\nconst compare = a =>\n b => a < b\n ? -1\n : a > b\n ? 1\n : 0;",
"compareList": "// compareList :: [a] -> [a] -> Ordering\nconst compareList = xs =>\n // 0 if two lists are identical.\n // -1 if xs is empty, or has a lower leftward value.\n // 1 if ys is empty, or has a lower leftward value.\n ys => compare(0 === xs.length)(0 === ys.length) || (\n compare(xs[0])(ys[0]) || (\n compareList(xs.slice(1))(ys.slice(1))\n )\n );",
"comparing": "// comparing :: Ord a => (b -> a) -> b -> b -> Ordering\nconst comparing = f =>\n // The ordering of f(x) and f(y) as a value\n // drawn from {-1, 0, 1}, representing {LT, EQ, GT}.\n x => y => {\n const\n a = f(x),\n b = f(y);\n\n return a < b\n ? -1\n : a > b\n ? 1\n : 0;\n };",
"compose": "// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c\nconst compose = (...fs) =>\n // A function defined by the right-to-left\n // composition of all the functions in fs.\n fs.reduce(\n (f, g) => x => f(g(x)),\n x => x\n );",
"composeList": "// composeList :: [(a -> a)] -> (a -> a)\nconst composeList = fs =>\n fs.reduce(\n (f, g) => x => f(g(x)),\n x => x\n );",
"composeListR": "// composeListR :: [(a -> a)] -> (a -> a)\nconst composeListR = fs =>\n x => fs.reduce((a, f) => f(a), x);",
"composeR": "// composeR (>>>) :: (a -> b) -> (b -> c) -> a -> c\nconst composeR = f =>\n g => x => f(g(x));",
"concat": "// concat :: [[a]] -> [a]\nconst concat = xs =>\n // The concatenation of all the lists\n // in a list of lists.\n xs.flat(1);",
"concatGen": "// concatGen :: Gen [[a]] -> Gen [a]\nconst concatGen = gen =>\n // A flattened stream of generator values;\n (function* (g) {\n let m = g.next();\n\n while (!m.done) {\n const xs = lazyList(m.value);\n let x = xs.next();\n\n while (!x.done) {\n yield x.value;\n x = xs.next();\n }\n m = g.next();\n }\n }(gen));",
"concatMap": "// concatMap :: (a -> [b]) -> [a] -> [b]\nconst concatMap = f =>\n // Concatenated results of a map of f over xs.\n // f is any function which returns a list value.\n // Any empty lists returned are filtered out by\n // the concatenation.\n xs => xs.flatMap(f);",
"concats": "// concats :: [String] -> String\nconst concats = xs =>\n xs.join(\"\");",
"cons": "// cons :: a -> [a] -> [a]\nconst cons = x =>\n // A list constructed from the item x,\n // followed by the existing list xs.\n xs => Array.isArray(xs)\n ? [x].concat(xs)\n : \"GeneratorFunction\" !== (\n xs.constructor.constructor.name\n )\n ? x + xs\n : (function *() {\n yield x;\n let nxt = xs.next();\n\n while (!nxt.done) {\n yield nxt.value;\n nxt = xs.next();\n }\n }());",
"constant": "// constant :: a -> b -> a\nconst constant = k =>\n () => k;",
"copyFileLR": "// copyFileLR :: FilePath -> FilePath -> Either String IO ()\nconst copyFileLR = fpFrom =>\n fpTo => {\n const fpTargetFolder = takeDirectory(fpTo);\n\n return doesFileExist(fpFrom)\n ? doesDirectoryExist(fpTargetFolder)\n ? (() => {\n const\n e = $(),\n fpTarget = $(fpTo).stringByStandardizingPath;\n\n return (\n $.NSFileManager.defaultManager\n .copyItemAtPathToPathError(\n $(fpFrom).stringByStandardizingPath,\n fpTarget,\n e\n )\n ? Right(ObjC.unwrap(fpTarget))\n : Left(ObjC.unwrap(e.localizedDescription))\n );\n })()\n : Left(`Target folder not found: ${fpTargetFolder}`)\n : Left(`Source file not found: ${fpFrom}`);\n };",
"createDirectoryIfMissingLR": "// createDirectoryIfMissingLR :: Bool -> FilePath\n// -> Either String FilePath\nconst createDirectoryIfMissingLR = blnParents =>\n dirPath => {\n const fp = filePath(dirPath);\n\n return doesPathExist(fp)\n ? Right(fp)\n : (() => {\n const\n e = $(),\n blnOK = $.NSFileManager\n .defaultManager[\n \"createDirectoryAtPath\" + (\n \"WithIntermediateDirectories\"\n ) + \"AttributesError\"\n ](fp, blnParents, void 0, e);\n\n return blnOK\n ? Right(fp)\n : Left(e.localizedDescription);\n })();\n };",
"curry": "// curry :: ((a, b) -> c) -> a -> b -> c\nconst curry = f =>\n a => b => 1 < f.length\n ? f(a, b)\n : f(Tuple(a)(b));",
"curryN": "// curryN :: Curry a b => a -> b\nconst curryN = f =>\n // A curried function derived from a\n // function over a tuple of any order.\n (...args) => {\n const\n go = xs => f.length <= xs.length\n ? f(...xs)\n : (...ys) => go(xs.concat(ys));\n\n return go(args);\n };",
"cycle": "// cycle :: [a] -> Generator [a]\nconst cycle = function* (xs) {\n // An infinite repetition of xs,\n // from which a prefix of arbitrary\n // length may be drawn.\n const n = xs.length;\n let i = 0;\n\n while (true) {\n yield xs[i];\n i = (1 + i) % n;\n }\n};",
"decodedPath": "// decodedPath :: Percent Encoded String -> FilePath\nconst decodedPath = decodeURI;",
"degrees": "// degrees :: Float x => Radians x -> Degrees x\nconst degrees = r =>\n (180 / Math.PI) * r;",
"delete": "// delete :: Eq a => a -> [a] -> [a]\nconst delete_ = x =>\n // xs with first instance of x (if any) removed.\n xs => {\n const i = xs.findIndex(v => x === v);\n\n return -1 === i\n ? xs.slice(0)\n : xs.slice(0, i).concat(\n xs.slice(1 + i)\n );\n };",
"deleteAt": "// deleteAt :: Int -> [a] -> [a]\nconst deleteAt = i =>\n // A copy of xs without any element at i, \n // if i is a valid index.\n xs => xs.slice(0, i).concat(\n xs.slice(1 + i)\n );",
"deleteBy": "// deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a]\nconst deleteBy = fEq =>\n // A copy of the given list excluding the first\n // item which matches x in terms of the supplied\n // fEq equality operator.\n x => xs => {\n const i = xs.findIndex(fEq(x));\n\n return -1 === i\n ? xs.slice(0)\n : xs.slice(0, i).concat(\n xs.slice(1 + i)\n );\n };",
"deleteFirst": "// deleteFirst :: a -> [a] -> [a]\nconst deleteFirst = x => {\n const go = xs => 0 < xs.length\n ? x === xs[0]\n ? xs.slice(1)\n : [...xs[0], ...go(xs.slice(1))]\n : [];\n\n return go;\n};",
"deleteFirstsBy": "// deleteFirstsBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]\nconst deleteFirstsBy = fEq =>\n // The first list purged of the first instance of\n // each predicate-matching element in the second list.\n xs => targets => {\n const d = deleteBy(fEq);\n\n return targets.reduce(\n (a, t) => d(t)(a),\n xs\n );\n };",
"deleteKey": "// deleteKey :: String -> Dict -> Dict\nconst deleteKey = k =>\n // A new dictionary, without the key k.\n dict => {\n const d = { ...dict };\n\n return (delete d[k], d);\n };",
"dictFromList": "// dictFromList :: [(k, v)] -> Dict\nconst dictFromList = kvs =>\n Object.fromEntries(kvs);",
"difference": "// difference :: Eq a => [a] -> [a] -> [a]\nconst difference = xs =>\n ys => {\n const s = new Set(ys);\n\n return xs.filter(x => !s.has(x));\n };",
"differenceGen": "// differenceGen :: Gen [a] -> Gen [a] -> Gen [a]\nconst differenceGen = ga =>\n function *(gb) {\n // All values of generator stream ga except any\n // already seen in generator stream gb.\n const\n stream = zipGen(ga)(gb),\n sb = new Set([]);\n\n let xy = take(1)(stream);\n\n while (Boolean(xy.length)) {\n const [x, y] = Array.from(xy[0]);\n\n sb.add(y);\n if (!sb.has(x)) {\n yield x;\n }\n xy = take(1)(stream);\n }\n };",
"digitToInt": "// digitToInt :: Char -> Int\nconst digitToInt = c => {\n const\n ord = x => x.codePointAt(0),\n oc = ord(c);\n\n return 48 > oc || 102 < oc\n ? null\n : (() => {\n const\n dec = oc - ord(\"0\"),\n hexu = oc - ord(\"A\"),\n hexl = oc - ord(\"a\");\n\n return 9 >= dec\n ? dec\n : 0 <= hexu && 5 >= hexu\n ? 10 + hexu\n : 0 <= hexl && 5 >= hexl\n ? 10 + hexl\n : null;\n })();\n};",
"div": "// div :: Int -> Int -> Int\nconst div = x =>\n y => Math.floor(x / y);",
"divMod": "// divMod :: Int -> Int -> (Int, Int)\nconst divMod = n => d => {\n // Integer division, truncated toward negative infinity,\n // and integer modulus such that:\n // (x `div` y)*y + (x `mod` y) == x\n const [q, r] = [Math.trunc(n / d), n % d];\n\n return signum(n) === signum(-d)\n ? Tuple(q - 1)(r + d)\n : Tuple(q)(r);\n};",
"doesDirectoryExist": "// doesDirectoryExist :: FilePath -> IO Bool\nconst doesDirectoryExist = fp => {\n const ref = Ref();\n\n return $.NSFileManager.defaultManager\n .fileExistsAtPathIsDirectory(\n $(fp)\n .stringByStandardizingPath, ref\n ) && ref[0];\n};",
"doesFileExist": "// doesFileExist :: FilePath -> IO Bool\nconst doesFileExist = fp => {\n const ref = Ref();\n\n return $.NSFileManager\n .defaultManager\n .fileExistsAtPathIsDirectory(\n $(fp).stringByStandardizingPath,\n ref\n ) && !ref[0];\n};",
"doesPathExist": "// doesPathExist :: FilePath -> IO Bool\nconst doesPathExist = fp =>\n $.NSFileManager.defaultManager\n .fileExistsAtPath(\n $(fp).stringByStandardizingPath\n );",
"dot": "// dot (.) :: (b -> c) -> (a -> b) -> a -> c\nconst dot = f =>\n // The composition of two functions.\n g => x => f(g(x));",
"draw": "// draw :: Tree String -> [String]\nconst draw = node => {\n // shifted :: String -> String -> [String] -> [String]\n const shifted = (first, other, xs) =>\n xs.map((x, i) =>\n (0 < i ? other : first) + x\n );\n\n // drawSubTrees :: [Tree String] -> [String]\n const drawSubTrees = xs => {\n const n = xs.length;\n\n return 0 < n\n ? [\"│\"].concat(\n 1 < n\n ? shifted(\"├─ \", \"│ \", draw(xs[0]))\n .concat(\n drawSubTrees(xs.slice(1))\n )\n : shifted(\"└─ \", \" \", draw(xs[0]))\n )\n : [];\n };\n\n return node.root.split(\"\\n\").concat(\n drawSubTrees(node.nest)\n );\n};",
"drawForest": "// drawForest :: [Tree String] -> String\nconst drawForest = trees =>\n trees.map(drawTree).join(\"\\n\");",
"drawTree": "// drawTree :: Tree String -> String\nconst drawTree = tree =>\n draw(tree).join(\"\\n\");",
"drawTree2": "// drawTree2 :: Bool -> Bool -> Tree String -> String\n// eslint-disable-next-line max-lines-per-function\nconst drawTree2 = blnCompact => blnPruned => tree => {\n // Tree design and algorithm inspired by the Haskell snippet at:\n // https://doisinkidney.com/snippets/drawing-trees.html\n const\n // Lefts, Middle, Rights\n lmrFromStrings = xs => {\n const [ls, rs] = Array.from(splitAt(\n Math.floor(xs.length / 2)\n )(xs));\n\n return TupleN(ls, rs[0], rs.slice(1));\n },\n stringsFromLMR = lmr =>\n Array.from(lmr).reduce((a, x) => a.concat(x), []),\n fghOverLMR = (f, g, h) => lmr => {\n const [ls, m, rs] = Array.from(lmr);\n\n return TupleN(ls.map(f), g(m), rs.map(h));\n };\n\n // eslint-disable-next-line max-lines-per-function\n const lmrBuild = (f, w) => wsTree => {\n const\n leftPad = n => s => \" \".repeat(n) + s,\n xs = wsTree.nest,\n lng = xs.length,\n [nChars, x] = Array.from(wsTree.root);\n\n // ------------------ LEAF NODE ------------------\n return 0 === lng\n ? TupleN([], \"─\".repeat(w - nChars) + x, [])\n\n // --------- NODE WITH SINGLE CHILD ----------\n : 1 === lng\n ? (() => {\n const indented = leftPad(1 + w);\n\n return fghOverLMR(\n indented,\n z => `${\"─\".repeat(w - nChars)}${x}-${z}`,\n indented\n )(f(xs[0]));\n\n // ----------- NODE WITH CHILDREN ------------\n })()\n : (() => {\n const\n cFix = y => ys => y + ys,\n treeFix = (l, m, r) => compose(\n stringsFromLMR,\n fghOverLMR(cFix(l), cFix(m), cFix(r))\n ),\n _x = \"─\".repeat(w - nChars) + x,\n indented = leftPad(w),\n lmrs = xs.map(f);\n\n return fghOverLMR(\n indented,\n s => _x + ({\n \"┌\": \"┬\",\n \"├\": \"┼\",\n \"│\": \"┤\",\n \"└\": \"┴\"\n })[s[0]] + s.slice(1),\n indented\n )(lmrFromStrings(\n intercalate(\n blnCompact\n ? []\n : [\"│\"]\n )(\n [treeFix(\" \", \"┌\", \"│\")(lmrs[0])]\n .concat(init(lmrs.slice(1)).map(\n treeFix(\"│\", \"├\", \"│\")\n ))\n .concat([treeFix(\"│\", \"└\", \" \")(\n lmrs[lmrs.length - 1]\n )])\n )\n ));\n })();\n };\n\n const\n measuredTree = fmapTree(\n v => {\n const s = ` ${v} `;\n\n return Tuple(s.length)(s);\n })(tree),\n levelWidths = levels(measuredTree)\n .reduce(\n (a, level) => a.concat(maximum(level.map(fst))),\n []\n ),\n treeLines = stringsFromLMR(\n levelWidths.reduceRight(\n lmrBuild, x => x\n )(measuredTree)\n );\n\n return unlines(\n blnPruned\n ? treeLines.filter(\n s => s.split(\"\")\n .some(c => !\" │\".includes(c))\n )\n : treeLines\n );\n};",
"drop": "// drop :: Int -> [a] -> [a]\n// drop :: Int -> Generator [a] -> Generator [a]\n// drop :: Int -> String -> String\nconst drop = n =>\n xs => Infinity > length(xs)\n ? xs.slice(n)\n : (take(n)(xs), xs);",
"dropAround": "// dropAround :: (a -> Bool) -> [a] -> [a]\n// dropAround :: (Char -> Bool) -> String -> String\nconst dropAround = p =>\n xs => dropWhile(p)(\n dropWhileEnd(p)(xs)\n );",
"dropFileName": "// dropFileName :: FilePath -> FilePath\nconst dropFileName = fp =>\n \"\" !== fp\n ? (() => {\n const\n xs = (fp.split(\"/\"))\n .slice(0, -1);\n\n return Boolean(xs.length)\n ? `${xs.join(\"/\")}/`\n : \"./\";\n })()\n : \"./\";",
"dropLength": "// dropLength :: [a] -> [b] -> [b]\nconst dropLength = xs =>\n ys => {\n const go = (x, y) =>\n 0 < x.length\n ? 0 < y.length\n ? go(x.slice(1), y.slice(1))\n : []\n : y;\n\n return go(xs, ys);\n };",
"dropLengthMaybe": "// dropLengthMaybe :: [a] -> [b] -> Maybe [b]\nconst dropLengthMaybe = xs =>\n ys => {\n const go = (x, y) =>\n Boolean(x.length) ? (\n Boolean(y.length) ? (\n go(x.slice(1), y.slice(1))\n ) : Nothing()\n ) : Just(y);\n\n return go(xs, ys);\n };",
"dropWhile": "// dropWhile :: (a -> Bool) -> [a] -> [a]\nconst dropWhile = p =>\n // The suffix remaining after takeWhile p xs.\n xs => {\n const i = xs.findIndex(x => !p(x));\n\n return -1 !== i\n ? xs.slice(i)\n : [];\n };",
"dropWhileEnd": "// dropWhileEnd :: (a -> Bool) -> [a] -> [a]\nconst dropWhileEnd = p =>\n // xs without the largest suffix in which p holds\n // for every element.\n xs => xs.slice(\n 0, 1 + xs.findLastIndex(\n x => !p(x)\n )\n );",
"dropWhileGen": "// dropWhileGen :: (a -> Bool) -> Gen [a] -> [a]\nconst dropWhileGen = p =>\n xs => {\n let\n nxt = xs.next(),\n v = nxt.value;\n\n while (!nxt.done && p(v)) {\n nxt = xs.next();\n v = nxt.value;\n }\n\n return cons(v)(xs);\n };",
"either": "// either :: (a -> c) -> (b -> c) -> Either a b -> c\nconst either = fl =>\n // Application of the function fl to the\n // contents of any Left value in e, or\n // the application of fr to its Right value.\n fr => e => \"Left\" in e\n ? fl(e.Left)\n : fr(e.Right);",
"elem": "// elem :: Eq a => a -> [a] -> Bool\nconst elem = x =>\n // True if xs contains an instance of x.\n xs => {\n const t = xs.constructor.name;\n\n return \"Array\" !== t\n ? xs[\"Set\" !== t\n ? \"includes\"\n : \"has\"](x)\n : xs.some(eq(x));\n };",
"elemAtMay": "// elemAtMay :: Int -> Dict -> Maybe (String, a)\n// elemAtMay :: Int -> [a] -> Maybe a\nconst elemAtMay = i =>\n // Just the item at the indexed position in an array,\n // or in the lexically sorted key-values of a dict,\n // or Nothing, if the index is out of range.\n obj => {\n const\n vs = Array.isArray(obj)\n ? obj\n : Object.entries(obj).sort(\n (a, b) => b[0].localeCompare(a[0])\n );\n\n return (0 <= i) && (i < vs.length)\n ? Just(vs[i])\n : Nothing();\n };",
"elemIndex": "// elemIndex :: Eq a => a -> [a] -> Maybe Int\nconst elemIndex = x =>\n // Just the index of x in xs, if it is found,\n // or Nothing, if xs does not contain x.\n xs => {\n const i = xs.indexOf(x);\n\n return -1 === i\n ? Nothing()\n : Just(i);\n };",
"elemIndices": "// elemIndices :: Eq a => a -> [a] -> [Int]\nconst elemIndices = x =>\n // The indices at which x occurs in xs.\n xs => [...xs].flatMap(\n (y, i) => y === x\n ? [i]\n : []\n );",
"elemTree": "// elemTree :: a -> Tree a -> Bool\nconst elemTree = x =>\n // True if the root of any node in the tree\n // has the value x.\n tree => {\n const go = t =>\n x === t.root || t.nest.some(go);\n\n return go(tree);\n };",
"elems": "// elems :: Map k a -> [a]\n// elems :: Set a -> [a]\nconst elems = x =>\n \"Set\" !== x.constructor.name\n ? Object.values(x)\n : Array.from(x.values());",
"encodedPath": "// encodedPath :: FilePath -> Percent Encoded String\nconst encodedPath = encodeURI;",
"enumFrom": "// enumFrom :: Enum a => a -> [a]\nconst enumFrom = function* (x) {\n // A non-finite succession of enumerable\n // values, starting with the value x.\n let v = x;\n\n while (true) {\n yield v;\n v = succ(v);\n }\n};",
"enumFromPairs": "// enumFromPairs :: String -> [(String, Int)] -> Dict\nconst enumFromPairs = enumName =>\n kvs => {\n const\n iMax = kvs[kvs.length - 1][1],\n iMin = kvs[0][1];\n\n return kvs.reduce(\n (a, kv) => ({\n ...a,\n [kv[0]]: {\n \"type\": \"enum\",\n \"name\": enumName,\n \"key\": kv[0],\n \"max\": iMax,\n \"min\": iMin,\n \"value\": kv[1]\n },\n [kv[1]]: kv[0]\n }), {}\n );\n };",
"enumFromThen": "// enumFromThen :: Int -> Int -> Gen [Int]\nconst enumFromThen = x =>\n // A non-finite stream of integers,\n // starting with x and y, and continuing\n // with the same interval.\n function* (y) {\n const d = y - x;\n let v = y + d;\n\n yield x;\n yield y;\n while (true) {\n yield v;\n v = d + v;\n }\n };",
"enumFromThenTo": "// enumFromThenTo :: Int -> Int -> Int -> [Int]\nconst enumFromThenTo = m =>\n // Integer values enumerated from m to n\n // with a step defined by (nxt - m).\n nxt => n => {\n const d = nxt - m;\n\n return Array.from({\n length: (Math.floor(n - nxt) / d) + 2\n }, (_, i) => m + (d * i));\n };",
"enumFromThenToChar": "// enumFromThenToChar :: Char -> Char -> Char -> [Char]\nconst enumFromThenToChar = x1 =>\n x2 => y => {\n const\n [i1, i2, iY] = [x1, x2, y].map(\n x => x.codePointAt(0)\n ),\n d = i2 - i1;\n\n return Array.from({\n length: (Math.floor(iY - i2) / d) + 2\n },\n (_, i) => String.fromCodePoint(\n i1 + (d * i)\n ));\n };",
"enumFromTo": "// enumFromTo :: Int -> Int -> [Int]\nconst enumFromTo = m =>\n // Enumeration of the integers from m to n.\n n => Array.from(\n {length: 1 + n - m},\n (_, i) => m + i\n );",
"enumFromToChar": "// enumFromToChar :: Char -> Char -> [Char]\nconst enumFromToChar = m => n => {\n const\n [intM, intN] = [m, n].map(\n x => x.codePointAt(0)\n );\n\n return Array.from({\n length: Math.floor(intN - intM) + 1\n }, (_, i) => String.fromCodePoint(intM + i));\n};",
"enumFromTo_": "// enumFromTo_ :: Enum a => a -> a -> [a]\nconst enumFromTo_ = m => n => {\n const\n [x, y] = [m, n].map(fromEnum),\n b = x + (\n isNaN(m)\n ? 0\n : m - x\n );\n\n return Array.from({\n length: 1 + (y - x)\n }, (_, i) => toEnum(m)(b + i));\n};",
"eq": "// eq (==) :: Eq a => a -> a -> Bool\nconst eq = a =>\n // True when a and b are equivalent in the terms\n // defined below for their shared data type.\n b => {\n const t = typeof a;\n\n return t === typeof b && (\n \"object\" !== t\n ? \"function\" !== t\n ? a === b\n : a.toString() === b.toString()\n : (() => {\n const kvs = Object.entries(a);\n\n return kvs.length !== Object.keys(b).length\n ? false\n : kvs.every(([k, v]) => eq(v)(b[k]));\n })()\n );\n };",
"eqDate": "// eqDate :: Date -> Date -> Bool\nconst eqDate = dte =>\n // True if the date parts of two date-time objects\n // (ignoring the time parts) are the same.\n dte1 => {\n const dayOnly = dateTime =>\n new Date(dateTime).setUTCHours(0, 0, 0, 0);\n\n return dayOnly(dte) === dayOnly(dte1);\n };",
"eqDateTime": "// eqDateTime :: Int -> Date -> Date -> Bool\nconst eqDateTime = n =>\n // Equivalence of two JS Date values\n // at a granularity of n minutes.\n // e.g.\n // Same minute: eqDateTime(1)(a)(b)\n // Same hour: eqDateTime(60)(a)(b)\n on(a => b => a === b)(\n flip(div)(6E4 * n)\n );",
"eqSet": "// eqSet :: Set a -> Set a -> Bool\nconst eqSet = a =>\n // True if the two sets have\n // the same size and members.\n b => a.size === b.size && (\n Array.from(a).every(x => b.has(x))\n );",
"evalJSLR": "// evalJSLR :: String -> Either String a\nconst evalJSLR = s => {\n try {\n // eslint-disable-next-line no-eval\n return Right(eval(`(${s})`));\n } catch (e) {\n return Left(e.message);\n }\n};",
"evalJSMay": "// evalJSMay :: String -> Maybe a\nconst evalJSMay = s => {\n try {\n // eslint-disable-next-line no-eval\n return Just(eval(`(${s})`));\n } catch (e) {\n return Nothing();\n }\n};",
"even": "// even :: Int -> Bool\nconst even = n =>\n // True if 2 is a factor of n.\n 0 === n % 2;",
"exp": "// exp :: Float -> Float\nconst exp = Math.exp;",
"fTable": "// fTable :: String -> (a -> String) ->\n// (b -> String) -> (a -> b) -> [a] -> String\nconst fTable = s =>\n // Heading -> x display function ->\n // fx display function ->\n // f -> values -> tabular string\n xShow => fxShow => f => xs => {\n const\n ys = xs.map(xShow),\n w = Math.max(...ys.map(y => [...y].length)),\n table = zipWith(\n a => b => `${a.padStart(w, \" \")} -> ${b}`\n )(ys)(\n xs.map(x => fxShow(f(x)))\n ).join(\"\\n\");\n\n return `${s}\\n${table}`;\n };",
"fType": "// fType :: (a -> f b) -> f\nconst fType = g => {\n const s = g.toString();\n\n return s.includes(\"Right\")\n ? Right\n : s.includes(\"Left\")\n ? Left\n : s.includes(\"Nothing\")\n ? Just\n : s.includes(\"Node\")\n ? flip(Node)([])\n : x => [x];\n};",
"fanArrow": "// fanArrow (&&&) ::\n// (a -> b) -> (a -> c) -> (a -> (b, c))\nconst fanArrow = f =>\n // A combined function, given f and g,\n // from x to a tuple of (f(x), g(x))\n // ((,) . f <*> g)\n g => x => Tuple(f(x))(\n g(x)\n );",
"filePath": "// filePath :: String -> FilePath\nconst filePath = s =>\n // The given file path with any tilde expanded\n // to the full user directory path.\n ObjC.unwrap(\n $(s).stringByStandardizingPath\n );",
"filePathTree": "// filePathTree :: filePath -> [Tree String] -> Tree FilePath\nconst filePathTree = fpAnchor =>\n trees => {\n const go = fp => tree => {\n const path = `${fp}/${tree.root.text}`;\n\n return Node(path)(\n tree.nest.map(go(path))\n );\n };\n\n return Node(fpAnchor)(\n trees.map(go(fpAnchor))\n );\n };",
"fileSize": "// fileSize :: FilePath -> Either String Int\nconst fileSize = fp =>\n bindLR(fileStatus(fp))(\n dct => Right(ObjC.unwrap(dct.NSFileSize))\n );",
"fileStatus": "// fileStatus :: FilePath -> Either String Dict\nconst fileStatus = fp => {\n const\n e = $(),\n dct = $.NSFileManager.defaultManager\n .attributesOfItemAtPathError(\n $(fp).stringByStandardizingPath,\n e\n );\n\n return dct.isNil()\n ? Left(ObjC.unwrap(e.localizedDescription))\n : Right(ObjC.deepUnwrap(dct));\n};",
"fileUTI": "// fileUTI :: FilePath -> Either String String\nconst fileUTI = fp => {\n // ObjC.import(\"AppKit\")\n const\n e = $(),\n uti = $.NSWorkspace.sharedWorkspace\n .typeOfFileError(fp, e);\n\n return uti.isNil()\n ? Left(ObjC.unwrap(e.localizedDescription))\n : Right(ObjC.unwrap(uti));\n};",
"filesCopiedLR": "// filesCopiedLR :: FilePath -> [FilePath] ->\n// FilePath -> IO Either String [FilePath]\nconst filesCopiedLR = fpSourceFolder =>\n // Either a message, or a list of the files\n // successfully copied from the source folder\n // to the target folder, or already found in place.\n fileNames => fpTargetFolder => {\n const\n lrs = fileNames.map(k => {\n const tgt = combine(fpTargetFolder)(k);\n\n return doesFileExist(tgt)\n ? Right(tgt)\n : copyFileLR(\n combine(fpSourceFolder)(k)\n )(tgt);\n }),\n ls = lefts(lrs);\n\n return 0 < ls.length\n ? Left(ls[0])\n : Right(rights(lrs));\n };",
"filter": "// filter :: (a -> Bool) -> [a] -> [a]\nconst filter = p =>\n // The elements of xs which match\n // the predicate p.\n xs => [...xs].filter(p);",
"filterGen": "// filterGen :: (a -> Bool) -> Gen [a] -> Gen [a]\nconst filterGen = p =>\n // A stream of values which are drawn\n // from a generator, and satisfy p.\n xs => {\n const go = function* () {\n let x = xs.next();\n\n while (!x.done) {\n const v = x.value;\n\n if (p(v)) {\n yield v;\n }\n x = xs.next();\n }\n };\n\n return go(xs);\n };",
"filterTree": "// filterTree (a -> Bool) -> Tree a -> [a]\nconst filterTree = p =>\n // List of all values in the tree\n // which match the predicate p.\n foldTree(x => xs =>\n p(x)\n ? [x, ...xs.flat()]\n : xs.flat()\n );",
"filteredForest": "// filteredForest :: (a -> Bool) -> [Tree a] -> [Tree a]\nconst filteredForest = p =>\n // A forest of trees which all subtrees match the predicate.\n trees => {\n const go = t => {\n const v = root(t);\n\n return p(v)\n ? [\n Node(v)(\n nest(t).flatMap(go)\n )\n ]\n : [];\n };\n\n return trees.flatMap(go);\n };",
"filteredSubTrees": "// filteredSubTrees :: (Tree a -> Bool) -> Tree a -> [Tree a]\nconst filteredSubTrees = p => {\n // SubTrees (within the given tree) which match p.\n const go = tree => (\n p(root(tree))\n ? [tree]\n : []\n )\n .concat(nest(tree).flatMap(go));\n\n return go;\n};",
"find": "// find :: (a -> Bool) -> [a] -> Maybe a\nconst find = p =>\n // Just the first element in xs which\n // matches the predicate p, or\n // Nothing if no match is found.\n xs => \"GeneratorFunction\" !== (\n xs.constructor.constructor.name\n )\n ? (() => {\n const i = xs.findIndex(p);\n\n return -1 !== i\n ? Just(xs[i])\n : Nothing();\n })()\n : findGen(p)(xs);",
"findGen": "// findGen :: (a -> Bool) -> Gen [a] -> Maybe a\nconst findGen = p =>\n // Just the first match for the predicate p\n // in the generator stream xs, or Nothing\n // if no match is found.\n xs => {\n const\n mb = until(\n ([nxt]) => nxt.done || p(nxt.value)\n )(\n ([, b]) => Tuple(b.next())(\n b\n )\n )(\n Tuple(xs.next())(xs)\n )[0];\n\n return mb.done\n ? Nothing()\n : Just(mb.value);\n };",
"findIndex": "// findIndex :: (a -> Bool) -> [a] -> Maybe Int\nconst findIndex = p =>\n // Just the index of the first element in\n // xs for which p(x) is true, or\n // Nothing if there is no such element.\n xs => {\n const i = [...xs].findIndex(p);\n\n return -1 !== i\n ? Just(i)\n : Nothing();\n };",
"findIndexR": "// findIndexR :: (a -> Bool) -> [a] -> Maybe Int\nconst findIndexR = p =>\n // Just the index of the last element in\n // xs for which p(x) is true, or\n // Nothing if there is no such element.\n xs => {\n const i = reverse([...xs]).findIndex(p);\n\n return -1 !== i\n ? Just(xs.length - (1 + i))\n : Nothing();\n };",
"findIndices": "// findIndices :: (a -> Bool) -> [a] -> [Int]\n// findIndices :: (String -> Bool) -> String -> [Int]\nconst findIndices = p =>\n xs => {\n const ys = [...xs];\n\n return ys.flatMap(\n (y, i) => p(y, i, ys)\n ? [i]\n : []\n );\n };",
"findTree": "// findTree :: (a -> Bool) -> Tree a -> Maybe a\nconst findTree = p => {\n // The first of any node values in the tree which match\n // the predicate p.\n // (For all matches, see treeMatches)\n const go = tree => {\n const x = tree.root;\n\n return p(x)\n ? Just(x)\n : (() => {\n const\n xs = tree.nest,\n n = xs.length;\n\n return 0 < n\n ? until(\n ([i, mb]) => n <= i || (\"Just\" in mb)\n )(\n ([i]) => [1 + i, go(xs[i])]\n )(\n [0, Nothing()]\n )[1]\n : Nothing();\n })();\n };\n\n return go;\n};",
"first": "// first :: (a -> b) -> ((a, c) -> (b, c))\nconst first = f =>\n // A simple function lifted to one which applies\n // to a tuple, transforming only its first item.\n ([x, y]) => Tuple(f(x))(y);",
"flatten": "// flatten :: NestedList a -> [a]\nconst flatten = nest =>\n nest.flat(Infinity);",
"flattenTree": "// flattenTree :: Tree a -> [a]\nconst flattenTree = tree => {\n const\n go = (xs, node) => [node.root].concat(\n node.nest.reduceRight(go, xs)\n );\n\n return go([], tree);\n};",
"flip": "// flip :: (a -> b -> c) -> b -> a -> c\nconst flip = op =>\n // The binary function op with\n // its arguments reversed.\n 1 !== op.length\n ? (a, b) => op(b, a)\n : (a => b => op(b)(a));",
"floor": "// floor :: Num -> Int\nconst floor = x => {\n const\n nr = (\n \"Ratio\" !== x.type\n ? properFraction\n : properFracRatio\n )(x),\n n = nr[0];\n\n return 0 > nr[1]\n ? n - 1\n : n;\n};",
"fmap": "// fmap (<$>) :: Functor f => (a -> b) -> f a -> f b\nconst fmap = f =>\n // f mapped over the given functor.\n x => ({\n \"Either\": () => fmapLR,\n \"(a -> b)\": () => dot,\n \"List\": () => map,\n \"Maybe\": () => fmapMay,\n \"Node\": () => fmapTree,\n \"String\": () => map,\n \"Tuple\": () => fmapTuple\n })[typeName(x)]()(f)(x);",
"fmapDict": "// fmapDict :: (a -> b) ->\n// {String :: a} -> {String :: b}\nconst fmapDict = f =>\n // A map of f over every value\n // in the given dictionary.\n dict => Object.entries(dict)\n .reduceRight(\n (a, [k, v]) => ({\n ...a,\n [k]: f(v)\n }),\n {}\n );",
"fmapGen": "// fmapGen <$> :: (a -> b) -> Gen [a] -> Gen [b]\nconst fmapGen = f =>\n // The map of f over a stream of generator values.\n function* (gen) {\n let v = gen.next();\n\n while (!v.done) {\n yield f(v.value);\n v = gen.next();\n }\n };",
"fmapLR": "// fmapLR (<$>) :: (b -> c) -> Either a b -> Either a c\nconst fmapLR = f =>\n // Either f mapped into the contents of any Right\n // value in e, or e unchanged if it is a Left value.\n e => \"Left\" in e\n ? e\n : Right(f(e.Right));",
"fmapMay": "// fmapMay (<$>) :: (a -> b) -> Maybe a -> Maybe b\nconst fmapMay = f =>\n mb => mb.Nothing\n ? mb\n : Just(f(mb.Just));",
"fmapTree": "// fmapTree :: (a -> b) -> Tree a -> Tree b\nconst fmapTree = f => {\n // A new tree. The result of a\n // structure-preserving application of f\n // to each root in the existing tree.\n const go = t => Node(\n f(root(t))\n )(\n nest(t).map(go)\n );\n\n return go;\n};",
"fmapTuple": "// fmapTuple (<$>) :: (a -> b) -> (a, a) -> (a, b)\nconst fmapTuple = f =>\n second(f);",
"fmapZL": "// fmapZL (<$>) :: (a -> b) -> ZipList a -> ZipList b\nconst fmapZL = f =>\n // f mapped over the contents of a ZipList\n // of finite or infinite length.\n zl => ZipList(\n (() => {\n const xs = zl.getZipList;\n\n return Infinity > xs.length\n ? xs.map(f)\n : fmapGen(f)(xs);\n })()\n );",
"foldList": "// foldList :: Monoid m => [m] -> m\nconst foldList = xs =>\n // The elements of xs combined.\n foldMapList(x => x)(xs);",
"foldMap": "// foldMap :: Monoid m => (a -> m) -> t a -> m\nconst foldMap = f => t =>\n // Each element of the structure mapped to a monoid,\n // with the results combined by (<>)\n ({\n Node: () => foldMapTree(f),\n List: () => foldMapList(f)\n })[typeName(t)]()(t);",
"foldMapGen": "// foldMapGen :: (a -> [b]) -> [a] -> Gen [b]\nconst foldMapGen = f =>\n // A lazy list of concatenated values\n // obtained by mapping f over xs\n xs => concatGen(\n function* () {\n const ys = [...xs];\n\n while (0 < ys.length) {\n yield f(ys.shift());\n }\n }(xs)\n );",
"foldMapList": "// foldMapList :: Monoid m => (a -> m) -> t a -> m\nconst foldMapList = f =>\n // f mapped over the combined values of a structure.\n xs => 1 < xs.length\n ? xs.slice(1).reduce(\n (a, x) => mappend(a)(f(x)),\n xs[0]\n )\n : xs.map(f);",
"foldMapTree": "// foldMapTree :: Monoid m => (a -> m) -> Tree a -> m\nconst foldMapTree = f => {\n // Result of mapping each element of the tree to\n // a monoid, and combining with mappend.\n const go = tree =>\n nest(tree).map(go)\n .reduce(\n uncurry(mappend),\n f(root(tree))\n );\n\n return go;\n};",
"foldTree": "// foldTree :: (a -> [b] -> b) -> Tree a -> b\nconst foldTree = f => {\n // The catamorphism on trees. A summary\n // value obtained by a depth-first fold.\n const go = tree => f(\n root(tree)\n )(\n nest(tree).map(go)\n );\n\n return go;\n};",
"foldl": "// foldl :: (a -> b -> a) -> a -> [b] -> a\nconst foldl = f =>\n // Note that that the signature of foldl differs\n // from that of foldr - the positions of\n // accumulator and current value in f are reversed.\n a => xs => [...xs].reduce(\n (x, y) => f(x)(y),\n a\n );",
"foldl1": "// foldl1 :: (a -> a -> a) -> [a] -> a\nconst foldl1 = f =>\n // Left to right reduction of the non-empty list xs,\n // using the binary operator f, with the head of xs\n // as the initial acccumulator value.\n xs => 1 < xs.length\n ? xs.slice(1).reduce(\n uncurry(f),\n xs[0]\n )\n : xs[0];",
"foldl1May": "// foldl1May :: (a -> a -> a) -> [a] -> Maybe a\nconst foldl1May = f =>\n xs => 0 < xs.length\n ? Just(\n xs.slice(1)\n .reduce(uncurry(f), xs[0])\n )\n : Nothing();",
"foldlTree": "// foldlTree :: (b -> a -> b) -> b -> Tree a -> b\nconst foldlTree = f =>\n // A top-down left-right\n // accumulating traversal.\n acc => node => {\n const go = (a, x) =>\n x.nest.reduce(go, f(a)(x.root));\n\n return go(acc, node);\n };",
"foldr": "// foldr :: (a -> b -> b) -> b -> [a] -> b\nconst foldr = f =>\n // Note that that the signature of foldr differs\n // from that of foldl - the positions of\n // current value and accumulator in f are reversed\n acc => xs => [...xs].reduceRight(\n (a, x) => f(x)(a),\n acc\n );",
"foldr1": "// foldr1 :: (a -> a -> a) -> [a] -> a\nconst foldr1 = f =>\n xs => 0 < xs.length\n ? xs.slice(0, -1).reduceRight(\n uncurry(f),\n xs.slice(-1)[0]\n )\n : [];",
"foldr1May": "// foldr1May :: (a -> a -> a) -> [a] -> Maybe a\nconst foldr1May = f =>\n // Nothing if xs is empty, or Just a right\n // fold of f over the list using the last\n // item of xs as the initial accumulator value.\n xs => Boolean(xs.length)\n ? Just(\n xs.slice(0, -1).reduceRight(\n uncurry(f),\n xs.slice(-1)[0])\n )\n : Nothing();",
"foldrTree": "// foldrTree :: (a -> b -> b) -> b -> Tree a -> b\nconst foldrTree = f =>\n acc => node => {\n const go = (a, x) =>\n f(x.root)(\n x.nest.reduceRight(go, a)\n );\n\n return go(acc, node);\n };",
"foldrTree2": "// foldrTree2 :: (a -> b -> b) -> b -> t a -> b\nconst foldrTree2 = f =>\n // A derivation of foldrTree\n // from foldMapTree\n z => t => foldMapTree(\n compose(Endo, f)\n )(t).appEndo(z);",
"foldr_": "// foldr_ :: (a -> b -> b) -> b -> t a -> b\nconst foldr_ = f =>\n // Reduction of a structure, in terms of a binary\n // operator, from right to left.\n // A generic foldr, applicable to trees as well\n // as to lists.\n z => t => appEndo(\n foldMap(\n compose(Endo, f)\n )(t)\n )(z);",
"forestFromJSONLR": "// forestFromJSONLR ::\n// JSON String -> Either String Forest a\nconst forestFromJSONLR = json => {\n // Either a message string or a Forest.\n // Assumes a recursive [root, nest] JSON format,\n // in which `root` is a parseable value string,\n // and `nest` is a possibly empty list of\n // [`root`, `nest`] pairs.\n const go = vxs =>\n Node(vxs[0])(\n vxs[1].map(go)\n );\n\n return fmapLR(\n xs => xs.map(go)\n )(\n jsonParseLR(json)\n );\n};",
"fromEnum": "// fromEnum :: Enum a => a -> Int\nconst fromEnum = x =>\n typeof x !== \"string\"\n ? x.constructor === Object\n ? x.value\n : parseInt(Number(x), 10)\n : x.codePointAt(0);",
"fromLeft": "// fromLeft :: a -> Either a b -> a\nconst fromLeft = def =>\n // The contents of a 'Left' value,\n // or otherwise a default value.\n lr => isLeft(lr)\n ? lr.Left\n : def;",
"fromMaybe": "// fromMaybe :: a -> Maybe a -> a\nconst fromMaybe = v =>\n mb => \"Nothing\" in mb\n ? v\n : mb.Just;",
"fromRight": "// fromRight :: b -> Either a b -> b\nconst fromRight = def =>\n // The contents of a 'Right' value or otherwise a default value.\n lr => isRight(lr) ? (\n lr.Right\n ) : def;",
"fst": "// fst :: (a, b) -> a\nconst fst = tpl =>\n // First member of a pair.\n tpl[0];",
"ft": "// ft :: Int -> Int -> [Int]\nconst ft = m =>\n // From To.\n // An abbreviation of enumFromTo.\n n => Array.from({\n length: 1 + n - m\n }, (_, i) => m + i);",
"gcd": "// gcd :: Integral a => a -> a -> a\nconst gcd = x =>\n y => {\n const zero = x.constructor(0);\n const go = (a, b) =>\n zero === b\n ? a\n : go(b, a % b);\n\n return go(abs(x), abs(y));\n };",
"gcdApprox": "// gcdApprox :: Real -> (Real, Real) -> Real\nconst gcdApprox = epsilon =>\n (x, y) => {\n const _gcd = (a, b) => (\n b < epsilon\n ? a\n : _gcd(b, a % b)\n );\n\n return _gcd(Math.abs(x), Math.abs(y));\n };",
"genericIndexMay": "// genericIndexMay :: [a] -> Int -> Maybe a\nconst genericIndexMay = xs =>\n i => (i < xs.length && 0 <= i)\n ? Just(xs[i])\n : Nothing();",
"getCurrentDirectory": "// getCurrentDirectory :: IO FilePath\nconst getCurrentDirectory = () =>\n ObjC.unwrap(\n $.NSFileManager.defaultManager\n .currentDirectoryPath\n );",
"getDirectoryContentsLR": "// getDirectoryContentsLR :: FilePath ->\n// Either String IO [FilePath]\nconst getDirectoryContentsLR = fp => {\n const\n error = $(),\n xs = $.NSFileManager.defaultManager\n .contentsOfDirectoryAtPathError(\n $(fp).stringByStandardizingPath,\n error\n );\n\n return xs.isNil()\n ? Left(ObjC.unwrap(error.localizedDescription))\n : Right(ObjC.deepUnwrap(xs));\n};",
"getHomeDirectory": "// getHomeDirectory :: IO FilePath\nconst getHomeDirectory = () =>\n ObjC.unwrap($.NSHomeDirectory());",
"getTemporaryDirectory": "// getTemporaryDirectory :: IO FilePath\nconst getTemporaryDirectory = () =>\n ObjC.unwrap($.NSTemporaryDirectory());",
"group": "// group :: [a] -> [[a]]\nconst group = xs =>\n // A list of lists, each containing only\n // elements equal under (===), such that the\n // concatenation of these lists is xs.\n groupBy(a => b => a === b)(xs);",
"groupBy": "// groupBy :: (a -> a -> Bool) -> [a] -> [[a]]\nconst groupBy = eqOp =>\n // A list of lists, each containing only elements\n // equal under the given equality operator, such\n // that the concatenation of these lists is xs.\n xs => 0 < xs.length\n ? (() => {\n const [h, ...t] = xs;\n const [groups, g] = t.reduce(\n ([gs, a], x) => eqOp(a[0])(x)\n ? [gs, [...a, x]]\n : [[...gs, a], [x]],\n [[], [h]]\n );\n\n return [...groups, g];\n })()\n : [];",
"groupOn": "// groupOn :: (a -> b) -> [a] -> [[a]]\nconst groupOn = f =>\n // A list of lists, each containing only elements\n // which return equal values for f,\n // such that the concatenation of these lists is xs.\n xs => 0 < xs.length\n ? groupBy(\n a => b => eq(a[0])(b[0])\n )(\n xs.map(x => [f(x), x])\n )\n .map(gp => gp.map(ab => ab[1]))\n : [];",
"groupOnKey": "// groupOnKey :: Eq k => (a -> k) -> [a] -> [(k, [a])]\nconst groupOnKey = f =>\n // A list of (k, [a]) tuples, in which each [a]\n // contains only elements for which f returns the\n // same value, and in which k is that value.\n // The concatenation of the [a] in each tuple === xs.\n xs => 0 < xs.length\n ? groupBy(a => b => a[0] === b[0])(\n xs.map(x => [f(x), x])\n )\n .map(gp => [\n gp[0][0],\n gp.map(ab => ab[1])\n ])\n : [];",
"groupSortBy": "// groupSortBy :: (a -> a -> Ordering) -> [a] -> [[a]]\nconst groupSortBy = f =>\n // e.g. groupSortBy(comparing(length))\n compose(\n groupBy(a => b => 0 === f(a)(b)),\n sortBy(f)\n );",
"groupSortOn": "// groupSortOn :: Ord b => (a -> b) -> [a] -> [[a]]\nconst groupSortOn = f =>\n compose(\n map(map(snd)),\n groupBy(on(eq)(fst)),\n sortBy(comparing(fst)),\n map(fanArrow(f)(identity))\n );",
"gt": "// gt :: Ord a => a -> a -> Bool\nconst gt = x => y =>\n \"Tuple\" === x.type\n ? x[0] > y[0]\n : (x > y);",
"head": "// head :: [a] -> a\nconst head = xs =>\n // The first item (if any) in a list.\n 0 < xs.length\n ? xs[0]\n : undefined;",
"headDef": "// headDef :: a -> [a] -> a\nconst headDef = v =>\n // The first item of a non-empty list,\n // or a default value if the list is empty.\n xs => Boolean(xs.length) ? (\n xs[0]\n ) : v;",
"headMay": "// headMay :: [a] -> Maybe a\nconst headMay = xs =>\n // Just the first item of xs, or\n // Nothing if xs is an empty list.\n 0 < xs.length\n ? Just(xs[0])\n : Nothing();",
"identity": "// identity :: a -> a\nconst identity = x =>\n // The identity function.\n x;",
"if_": "// if_ :: Bool -> a -> a -> a\nconst if_ = bln =>\n x => y => bln\n ? x\n : y;",
"indented": "// indented :: String -> String -> String\nconst indented = indent =>\n s => lines(s).map(\n x => 0 < x.length\n ? indent + x\n : x\n )\n .join(\"\\n\");",
"index": "// index (!!) :: [a] -> Int -> Maybe a\n// index (!!) :: Generator (Int, a) -> Int -> Maybe a\n// index (!!) :: String -> Int -> Maybe Char\nconst index = xs =>\n i => {\n const s = xs.constructor.constructor.name;\n\n return \"GeneratorFunction\" !== s\n ? (() => {\n const v = xs[i];\n\n return undefined !== v\n ? Just(v)\n : Nothing();\n })()\n : (take(i)(xs), xs.next().value);\n };",
"indexForest": "// indexForest :: [Tree (a, { nodeSum :: Int })] -> Int ->\n// Maybe Tree (a, { nodeSum :: Int })\nconst indexForest = trees =>\n // Index into a forest of measured trees.\n // (see measuredTree)\n i => 0 < trees.length\n ? (() => {\n const\n headNode = trees[0],\n headSize = headNode.root[1].nodeSum;\n\n return i > (headSize - 1)\n ? indexForest(trees.slice(1))(i - headSize)\n : indexTree(headNode)(i);\n })()\n : Nothing();",
"indexOf": "// indexOf :: Eq a => [a] -> [a] -> Maybe Int\n// indexOf :: String -> String -> Maybe Int\nconst indexOf = needle =>\n haystack => \"string\" !== typeof haystack\n ? findIndex(xs => isPrefixOf(needle)(xs))(\n tails(haystack)\n )\n : (() => {\n const i = haystack.indexOf(needle);\n\n return -1 !== i\n ? Just(i)\n : Nothing();\n })();",
"indexTree": "// indexTree :: Tree (a, { nodeSum :: Int }) -> Int ->\n// Maybe Tree (a, { nodeSum :: Int })\nconst indexTree = tree =>\n // Index into a measured tree. (see measuredTree)\n i => 0 !== i\n ? i > (tree.root[1].nodeSum - 1)\n ? Nothing()\n : indexForest(tree.nest)(i - 1)\n : Just(tree);",
"indexedTree": "// indexedTree :: Int -> Tree a -> Tree (a, Int)\nconst indexedTree = rootIndex =>\n // A tree in which each root value\n // is paired with a top-down\n // left-right index, where the root node\n // starts at the supplied rootIndex;\n tree => mapAccumLTree(\n i => x => Tuple(1 + i)(\n Tuple(x)({\n index: i\n })\n )\n )(rootIndex)(tree)[1];",
"init": "// init :: [a] -> [a]\nconst init = xs =>\n // All elements of a list except the last.\n 0 < xs.length\n ? xs.slice(0, -1)\n : null;",
"initMay": "// initMay :: [a] -> Maybe [a]\nconst initMay = xs =>\n 0 < xs.length\n ? Just(xs.slice(0, -1))\n : Nothing();",
"inits": "// inits :: [a] -> [[a]]\n// inits :: String -> [String]\nconst inits = xs =>\n // All prefixes of the argument,\n // shortest first.\n [[], ...xs].map(\n (_, i, ys) => ys.slice(0, 1 + i)\n );",
"insert": "// insert :: Ord a => a -> [a] -> [a]\nconst insert = x =>\n xs => {\n const i = xs.findIndex(y => y >= x);\n\n return [\n ...xs.slice(0, i),\n x,\n ...xs.slice(i)\n ];\n };",
"insertBy": "// insertBy :: (a -> a -> Ordering) -> a -> [a] -> [a]\nconst insertBy = cmp =>\n // A new list in in which x is inserted into the\n // values of the given list at the first position\n // at which a supplied comparison function, applied\n // to x and the following value, returns LT or EQ.\n x => xs => {\n const go = (y, ys) =>\n 0 < ys.length\n ? 0 < cmp(y)(ys[0])\n ? [ys[0], ...go(y, ys.slice(1))]\n : [y, ...ys]\n : [y];\n\n return go(x, xs);\n };",
"insertDict": "// insertDict :: String -> a -> Dict -> Dict\nconst insertDict = k =>\n v => dict => ({\n ...dict,\n [k]: v\n });",
"insertWith": "// insertWith :: Ord k => (a -> a -> a) ->\n// k -> a -> Map k a -> Map k a\nconst insertWith = f =>\n // A new dictionary updated with a (k, f(v)(x)) pair.\n // Where there is no existing v for k, the supplied\n // x is used directly.\n k => x => dict => ({\n ...dict,\n [k]: k in dict\n ? f(dict[k])(x)\n : x\n });",
"intToDigit": "// intToDigit :: Int -> Char\nconst intToDigit = n =>\n n >= 0 && n < 16\n ? \"0123456789ABCDEF\".charAt(n)\n : \"?\";",
"intercalate": "// intercalate :: [a] -> [[a]] -> [a]\nconst intercalate = sep =>\n // Flattened interspersal of a list between\n // the elements of a list of lists.\n xs => intersperse(sep)(xs).flat();",
"intercalateS": "// intercalateS :: String -> [String] -> String\nconst intercalateS = s =>\n // The concatenation of xs\n // interspersed with copies of s.\n xs => xs.join(s);",
"intersect": "// intersect :: (Eq a) => [a] -> [a] -> [a]\nconst intersect = xs =>\n // The intersection of lists xs and ys.\n ys => xs.filter(x => ys.includes(x));",
"intersectBy": "// intersectBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]\nconst intersectBy = eqFn =>\n // The intersection of the lists xs and ys\n // in terms of the equality defined by eq.\n xs => ys => xs.filter(\n x => ys.some(eqFn(x))\n );",
"intersectListsBy": "// intersectListsBy :: (a -> a -> Bool) -> [[a]] -> [a]\nconst intersectListsBy = eqFn =>\n foldr1(intersectBy(eqFn));",
"intersectSet": "// intersectSet :: Set -> Set -> Set\nconst intersectSet = a =>\n // The intersection of two sets.\n b => new Set([...a].filter(i => b.has(i)));",
"intersection": "// intersection :: Ord a => Set a -> Set a -> Set a\nconst intersection = s => s1 =>\n new Set([...s].filter(x => s1.has(x)));",
"intersperse": "// intersperse :: a -> [a] -> [a]\nconst intersperse = sep =>\n // intersperse(0)([1,2,3]) -> [1, 0, 2, 0, 3]\n xs => 0 < xs.length\n ? [xs[0]].concat(\n xs.slice(1).flatMap(x => [sep, x])\n )\n : [];",
"isAlpha": "// isAlpha :: Char -> Bool\nconst isAlpha = c =>\n (/[A-Za-z\\u00C0-\\u00FF]/u).test(c);",
"isAlphaNum": "// isAlphaNum :: Char -> Bool\nconst isAlphaNum = c => {\n const n = c.codePointAt(0);\n\n return (48 <= n && 57 >= n) || (\n (/[A-Za-z\\u00C0-\\u00FF]/u).test(c)\n );\n};",
"isBigInt": "// isBigInt :: Num -> Bool\nconst isBigInt = n =>\n (\"undefined\" !== typeof BigInt) && (\n \"bigint\" === typeof n\n );",
"isChar": "// isChar :: a -> Bool\nconst isChar = x =>\n (\"string\" === typeof x) && (1 === x.length);",
"isDigit": "// isDigit :: Char -> Bool\nconst isDigit = c => {\n const n = c.codePointAt(0);\n\n return 48 <= n && 57 >= n;\n};",
"isInfixOf": "// isInfixOf :: (Eq a) => [a] -> [a] -> Bool\n// isInfixOf :: String -> String -> Bool\nconst isInfixOf = needle => haystack =>\n \"string\" !== typeof haystack\n ? (() => {\n const\n lng = needle.length,\n go = xs => lng <= xs.length\n ? isPrefixOf(needle)(xs) || go(xs.slice(1))\n : false;\n\n return go(haystack);\n })()\n : haystack.includes(needle);",
"isLeft": "// isLeft :: Either a b -> Bool\nconst isLeft = lr =>\n (\"Either\" === lr.type) && (undefined !== lr.Left);",
"isLower": "// isLower :: Char -> Bool\nconst isLower = c =>\n // True if c is a lower case character.\n (/\\p{Ll}/u).test(c);",
"isMaybe": "// isMaybe :: a -> Bool\nconst isMaybe = x =>\n \"Maybe\" === x.type;",
"isNull": "// isNull :: [a] -> Bool\n// isNull :: String -> Bool\nconst isNull = xs =>\n// True if xs is empty.\n 1 > xs.length;",
"isPrefixOf": "// isPrefixOf :: [a] -> [a] -> Bool\n// isPrefixOf :: String -> String -> Bool\nconst isPrefixOf = xs =>\n// True if and only if xs is a prefix of ys.\n ys => {\n const go = (vs, ws) => {\n const intX = vs.length;\n\n return 0 < intX\n ? ws.length >= intX\n ? vs[0] === ws[0] && go(\n vs.slice(1), ws.slice(1)\n )\n : false\n : true;\n };\n\n return \"string\" !== typeof xs\n ? go(xs, ys)\n : ys.startsWith(xs);\n };",
"isRight": "// isRight :: Either a b -> Bool\nconst isRight = lr =>\n (\"undefined\" !== typeof lr) && (\n \"Either\" === lr.type\n ) && (undefined !== lr.Right);",
"isSortedBy": "// isSortedBy :: (a -> a -> Bool) -> [a] -> Bool\nconst isSortedBy = p =>\n // True if all adjacent pairs of elements in\n // the list return True under the predicate p.\n xs => xs.length < 2 || all(x => x < 1)(\n zipWith_(p)(\n xs\n )(tail(xs))\n );",
"isSpace": "// isSpace :: Char -> Bool\nconst isSpace = c =>\n // True if c is a white space character.\n (/\\s/u).test(c);",
"isSubsequenceOf": "// isSubsequenceOf :: Eq a => [a] -> [a] -> Bool\n// isSubsequenceOf :: String -> String -> Bool\nconst isSubsequenceOf = xs =>\n // True if xs is a sub-sequence of ys.\n ys => {\n const go = (a, b) =>\n 0 < a.length\n ? 0 < b.length\n ? go(\n a[0] === b[0]\n ? a.slice(1)\n : a,\n b.slice(1)\n )\n : false\n : true;\n\n return go(xs, ys);\n };",
"isSubsetOf": "// isSubsetOf :: Ord a => Set a -> Set a -> Bool\nconst isSubsetOf = a => b => {\n for (const x of a) {\n if (!b.has(x)) {\n return false;\n }\n }\n\n return true;\n};",
"isSuffixOf": "// isSuffixOf :: Eq a => [a] -> [a] -> Bool\n// isSuffixOf :: String -> String -> Bool\nconst isSuffixOf = needle =>\n haystack => \"string\" !== typeof haystack\n ? bindMay(\n dropLengthMaybe(needle)(haystack)\n )(\n delta => eq(needle)(\n dropLength(delta)(haystack)\n )\n )\n : haystack.endsWith(needle);",
"isUpper": "// isUpper :: Char -> Bool\nconst isUpper = c =>\n // True if c is an upper case character.\n (/\\p{Lu}/u).test(c);",
"iso8601Local": "// iso8601Local :: Date -> String\nconst iso8601Local = dte =>\n new Date(dte - (6E4 * dte.getTimezoneOffset()))\n .toISOString();",
"iterate": "// iterate :: (a -> a) -> a -> Gen [a]\nconst iterate = f =>\n // An infinite list of repeated applications\n // of f, starting with the seed value x.\n function* (x) {\n let v = x;\n\n while (true) {\n yield v;\n v = f(v);\n }\n };",
"iterateUntil": "// iterateUntil :: (a -> Bool) -> (a -> a) -> a -> [a]\nconst iterateUntil = p =>\n // Like `until`, but returns a list of\n // intermediate values, where until\n // returns only a final value.\n // iterateUntil(x => 5 < x)(x => 2 * x)(1)\n // -> [1, 2, 4, 8]\n f => x => {\n const\n go = v => p(v)\n ? [v]\n : [v, ...go(f(v))];\n\n return go(x);\n };",
"iterateUntilGen": "// iterateUntilGen :: (a -> Bool) -> (a -> a) ->\n// a -> Generator [a]\nconst iterateUntilGen = p =>\n f => function* (x) {\n let v = x;\n\n while (!p(v)) {\n yield v;\n v = f(v);\n }\n };",
"join": "// join :: Monad m => m (m a) -> m a\nconst join = x =>\n bind(x)(identity);",
"jsonFromTree": "// jsonFromTree :: Tree a -> String\nconst jsonFromTree = tree => {\n // A recursive [root, nest] JSON format,\n // in which `root` is a value string, and `nest`\n // is a possibly empty list of [`root`, `nest`] pairs.\n const go = node => [node.root, node.nest.map(go)];\n\n return JSON.stringify(go(tree));\n};",
"jsonLog": "// jsonLog :: a -> IO ()\nconst jsonLog = (...args) =>\n // eslint-disable-next-line no-console\n console.log(\n args\n .map(JSON.stringify)\n .join(\" -> \")\n );",
"jsonParseLR": "// jsonParseLR :: String -> Either String a\nconst jsonParseLR = s => {\n try {\n return Right(JSON.parse(s));\n } catch (e) {\n return Left(\n unlines([\n e.message,\n `(line:${e.line} col:${e.column})`\n ])\n );\n }\n};",
"justifyLeft": "// justifyLeft :: Int -> Char -> String -> String\nconst justifyLeft = n =>\n // The string s, followed by enough padding (with\n // the character c) to reach the string length n.\n c => s => n > s.length\n ? s.padEnd(n, c)\n : s;",
"justifyRight": "// justifyRight :: Int -> Char -> String -> String\nconst justifyRight = n =>\n // The string s, preceded by enough padding (with\n // the character c) to reach the string length n.\n c => s => n > s.length\n ? s.padStart(n, c)\n : s;",
"kCompose": "// kCompose (>=>) :: Monad m =>\n// [(a -> m a)] -> (a -> m a)\nconst kCompose = (...fs) =>\n // Left Right composition of a sequence\n // of functions which lift a raw value\n // of the same type into the same monad.\n x => Boolean(fs.length)\n ? fs.slice(1).reduce(\n (m, f) => bind(m)(f),\n fs[0](x)\n )\n : x;",
"keys": "// keys :: Dict -> [String]\nconst keys = Object.keys;",
"kleisliCompose": "// kleisliCompose (>=>) :: Monad m => (a -> m b) ->\n// (b -> m c) -> (a -> m c)\nconst kleisliCompose = f =>\n // Kleisli composition of two functions which\n // each lift their values into the same monad.\n g => x => bind(f(x))(g);",
"last": "// last :: [a] -> a\nconst last = xs => {\n // The last item of a list.\n const n = xs.length;\n\n return 0 < n\n ? xs[n - 1]\n : null;\n};",
"lastMay": "// lastMay :: [a] -> Maybe a\nconst lastMay = xs =>\n // Nothing if xs is empty, otherwise\n // Just the last item of xs.\n 0 < xs.length\n ? Just(xs.slice(-1)[0])\n : Nothing();",
"lazyList": "// lazyList :: [a] -> Gen [a]\nconst lazyList = xs => {\n // The values of a given array\n // lazily yielded one by one.\n const go = function* () {\n const vs = Array.from(xs);\n\n while (0 < vs.length) {\n yield vs.shift();\n }\n };\n\n return go();\n};",
"lcm": "// lcm :: Int -> Int -> Int\nconst lcm = x =>\n // The smallest positive integer divisible\n // without remainder by both x and y.\n y => (x === 0 || y === 0)\n ? 0\n : Math.abs(Math.floor(x / gcd(x)(y)) * y);",
"le": "// le :: Ord a => a -> a -> a\nconst le = x =>\n // True if x <= y;\n y => x <= y;",
"lefts": "// lefts :: [Either a b] -> [a]\nconst lefts = xs =>\n xs.flatMap(\n x => (\"Left\" in x)\n ? [x.Left]\n : []\n );",
"length": "// length :: [a] -> Int\nconst length = xs =>\n // Returns Infinity over objects without finite\n // length. This enables zip and zipWith to choose\n // the shorter argument when one is non-finite,\n // like cycle, repeat etc\n \"Node\" !== xs.type\n ? \"GeneratorFunction\" !== (\n xs.constructor.constructor.name\n )\n ? xs.length\n : Infinity\n : lengthTree(xs);",
"lengthTree": "// lengthTree :: Tree a -> Int\nconst lengthTree = tree => {\n // The number of nodes in the tree.\n const go = (n, t) =>\n n + nest(t).reduce(go, 1);\n\n return go(0, tree);\n};",
"levelNodes": "// levelNodes :: Tree a -> [[Tree a]]\nconst levelNodes = tree =>\n iterateUntil(xs => 1 > xs.length)(\n xs => xs.flatMap(x => x.nest)\n )([tree]);",
"levels": "// levels :: Tree a -> [[a]]\nconst levels = tree => {\n // A list of lists, grouping the root\n // values of each level of the tree.\n const go = (layers, t) => {\n const\n [x, ...xs] = (\n 0 < layers.length\n )\n ? layers\n : [[]];\n\n return [\n x.concat(root(t)),\n ...nest(t).reduce(go, xs)\n ];\n };\n\n return go([], tree);\n};",
"liftA2": "// liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c\nconst liftA2 = f =>\n // Lift a binary function to actions.\n // liftA2 f a b = fmap f a <*> b\n a => b => ({\n \"(a -> b)\": () => liftA2Fn,\n \"Either\": () => liftA2LR,\n \"Maybe\": () => liftA2May,\n \"Tuple\": () => liftA2Tuple,\n \"Node\": () => liftA2Tree,\n \"List\": () => liftA2List,\n \"Bottom\": () => liftA2List\n }[typeName(a) || \"List\"]())(f)(a)(b);",
"liftA2Fn": "// liftA2Fn :: (a0 -> b -> c) -> (a -> a0) -> (a -> b) -> a -> c\nconst liftA2Fn = op =>\n // Lift a binary function to a composition\n // over two other functions.\n // liftA2 (*) (+ 2) (+ 3) 7 == 90\n f => g => x => op(f(x))(\n g(x)\n );",
"liftA2LR": "// liftA2LR :: (a -> b -> c) -> Either d a -> Either d b -> Either d c\nconst liftA2LR = f =>\n // The binary function f lifted to a\n // function over two Either values.\n a => b => bindLR(a)(\n x => bindLR(b)(\n compose(Right, f(x))\n )\n );",
"liftA2List": "// liftA2List :: (a -> b -> c) -> [a] -> [b] -> [c]\nconst liftA2List = op =>\n // The binary operator op applied to each pair of\n // arguments in the cartesian product of xs and ys.\n // A binary operator lifed to a function over two lists.\n xs => ys => xs.flatMap(\n x => ys.map(op(x))\n );",
"liftA2May": "// liftA2May :: (a -> b -> c) -> Maybe a -> Maybe b -> Maybe c\nconst liftA2May = f =>\n a => b => a.Nothing\n ? a\n : b.Nothing\n ? b\n : Just(f(a.Just)(b.Just));",
"liftA2Tree": "// liftA2Tree :: (a -> b -> c) -> Tree a -> Tree b -> Tree c\nconst liftA2Tree = f =>\n tx => ty => {\n const go = t =>\n Node(f(t.root)(ty.root))(\n Boolean(ty.nest)\n ? ty.nest.map(\n fmapTree(f(t.root))\n )\n .concat(t.nest.map(go))\n : []\n );\n\n return go(tx);\n };",
"liftA2Tuple": "// liftA2Tuple :: Monoid m =>\n// (a -> b -> c) -> (m, a) -> (m, b) -> (m, c)\nconst liftA2Tuple = f =>\n ([a, b]) => ([c, d]) => Tuple(\n mappend(a)(c)\n )(\n f(b)(d)\n );",
"liftA2ZL": "// liftA2ZL :: (a -> b -> c) -> ZipList a ->\n// ZipList b -> ZipList c\nconst liftA2ZL = op =>\n // A ZipList formed by the pairwise application of a\n // binary op over the values of two existing ZipLists\n // up to the length of the shorter of these.\n zxs => zys => ZipList(\n zipWith(op)(\n zxs.getZipList\n )(\n zys.getZipList\n )\n );",
"lines": "// lines :: String -> [String]\nconst lines = s =>\n // A list of strings derived from a single string\n // which is delimited by \\n or by \\r\\n or \\r.\n 0 < s.length\n ? s.split(/\\r\\n|\\n|\\r/u)\n : [];",
"list": "// list :: StringOrArrayLike b => b -> [a]\nconst list = xs =>\n// xs itself, if it is an Array,\n// or an Array derived from xs.\n Array.isArray(xs)\n ? xs\n : Array.from(xs || []);",
"listDirectory": "// listDirectory :: FilePath -> [FilePath]\nconst listDirectory = fp =>\n ObjC.deepUnwrap(\n $.NSFileManager.defaultManager\n .contentsOfDirectoryAtPathError(\n $(fp).stringByStandardizingPath,\n null\n )\n );",
"listFromMaybe": "// listFromMaybe :: Maybe a -> [a]\nconst listFromMaybe = mb =>\n // A singleton list derived from a Just value,\n // or an empty list derived from Nothing.\n mb.Nothing\n ? []\n : [mb.Just];",
"listFromTree": "// listFromTree :: Tree a -> [a]\nconst listFromTree = tree => {\n const go = x => [\n root(x),\n ...[].concat(...nest(x).map(go))\n ];\n\n return go(tree);\n};",
"listToMaybe": "// listToMaybe :: [a] -> Maybe a\nconst listToMaybe = xs =>\n // Nothing if xs is empty, or Just the head of xs.\n 0 < xs.length\n ? Just(xs[0])\n : Nothing();",
"log": "// log :: Float -> Float\nconst log = Math.log;",
"lookup": "// lookup :: Eq a => a -> Container -> Maybe b\nconst lookup = k =>\n // Just of value of the key k in m,\n // or Nothing if m does not contain k.\n m => (Array.isArray(m)\n ? lookupTuples\n : lookupDict)(k)(m);",
"lookupDict": "// lookupDict :: a -> Dict -> Maybe b\nconst lookupDict = k =>\n dct => {\n const v = dct[k];\n\n return undefined !== v\n ? Just(v)\n : Nothing();\n };",
"lookupTuples": "// lookupTuples :: Eq a => a -> [(a, b)] -> Maybe b\nconst lookupTuples = k =>\n kvs => {\n const i = kvs.findIndex(kv => k === kv[0]);\n\n return -1 !== i\n ? Just(kvs[i][1])\n : Nothing();\n };",
"lt": "// lt (<) :: Ord a => a -> a -> Bool\nconst lt = a =>\n b => a < b;",
"mReturn": "// mReturn :: First-class m => (a -> b) -> m (a -> b)\nconst mReturn = x =>\n // Not required in JS, which has first functions by default.\n // Included only for comparison with AS, which has to derive\n // first class functions by lifting 'handlers' into 'scripts'\n // as anonymous |λ|() functions.\n // In JS, mReturn is just an alias of identity.\n identity(x);",
"map": "// map :: (a -> b) -> [a] -> [b]\nconst map = f =>\n // The list obtained by applying f\n // to each element of xs.\n // (The image of xs under f).\n xs => [...xs].map(f);",
"mapAccumL": "// mapAccumL :: (acc -> x -> (acc, y)) -> acc ->\n// [x] -> (acc, [y])\nconst mapAccumL = f =>\n // A tuple of an accumulation and a list\n // obtained by a combined map and fold,\n // with accumulation from left to right.\n acc => xs => [...xs].reduce(\n ([a, bs], x) => second(\n v => [...bs, v]\n )(\n f(a)(x)\n ),\n [acc, []]\n );",
"mapAccumLTree": "// mapAccumLTree :: (s -> a -> (s, b)) -> s ->\n// Tree a -> (s, Tree b)\nconst mapAccumLTree = f => {\n // A tuple of an accumulation and a tree\n // obtained by a combined map and fold,\n // with accumulation from left to right over\n // the subForest.\n const go = a => x => {\n const [acc, v] = f(a)(root(x));\n\n return second(Node(v))(\n mapAccumL(go)(acc)(nest(x))\n );\n };\n\n return go;\n};",
"mapAccumR": "// mapAccumR :: (acc -> x -> (acc, y)) -> acc ->\n// [x] -> (acc, [y])\nconst mapAccumR = f =>\n // A tuple of an accumulation and a list\n // obtained by a combined map and fold,\n // with accumulation from right to left.\n acc => xs => [...xs].reduceRight(\n ([a, b], x) => second(\n v => [v].concat(b)\n )(\n f(a)(x)\n ),\n Tuple(acc)([])\n );",
"mapFromList": "// mapFromList :: [(String, a)] -> Dict\nconst mapFromList = kvs =>\n Object.fromEntries(kvs);",
"mapKeys": "// mapKeys :: (Key -> Key) -> IntMap a -> IntMap a\nconst mapKeys = f =>\n // A function mapped over the keys of a record,\n // defining a new record.\n dct => Object.fromEntries(\n Object.entries(dct)\n .map(kv => [f(kv[0]), kv[1]])\n );",
"mapMaybe": "// mapMaybe :: (a -> Maybe b) -> [a] -> [b]\nconst mapMaybe = mf =>\n // A filtered map, retaining only the contents\n // of Just values. (Nothing values discarded).\n xs => xs.flatMap(x => {\n const mb = mf(x);\n\n return \"Just\" in mb\n ? [mb.Just]\n : [];\n });",
"mapMaybeGen": "// mapMaybeGen :: (a -> Maybe b) -> Gen [a] -> Gen [b]\nconst mapMaybeGen = mf =>\n // A filtered map over a generator, returning only the\n // contents of Just values. (Nothing values discarded).\n function*(gen) {\n let v = take(1)(gen);\n\n while (Boolean(v.length)) {\n const mb = mf(v[0]);\n\n if (!(\"Nothing\" in mb)) {\n yield mb.Just;\n }\n v = take(1)(gen);\n }\n };",
"mappEndo": "// mappEndo (<>) :: Endo a -> Endo a -> Endo a\nconst mappEndo = a =>\n // mappend is defined as composition\n // for the Endo type.\n b => Endo(x => a.appEndo(b.appEndo(x)));",
"mappend": "// mappend (<>) :: Monoid a => a -> a -> a\nconst mappend = a =>\n // Associative operation\n // defined for various monoids.\n ({\n \"(a -> b)\": () => mappendFn,\n \"Endo\": () => mappEndo,\n \"List\": () => append,\n \"Maybe\": () => mappendMaybe,\n \"Num\": () => mappendOrd,\n \"String\": () => append,\n \"Tuple\": () => mappendTupleN,\n \"TupleN\": () => mappendTupleN\n })[typeName(a)]()(a);",
"mappendComparing": "// mappendComparing (<>) :: (a -> a -> Bool)\n// (a -> a -> Bool) -> (a -> a -> Bool)\nconst mappendComparing = cmp =>\n cmp1 => a => b => {\n const x = cmp(a)(b);\n\n return 0 !== x\n ? x\n : cmp1(a)(b);\n };",
"mappendFn": "// mappendFn (<>) :: Monoid b => (a -> b) -> (a -> b) -> (a -> b)\nconst mappendFn = f =>\n g => x => mappend(f(x))(\n g(x)\n );",
"mappendMaybe": "// mappendMaybe (<>) :: Maybe a -> Maybe a -> Maybe a\nconst mappendMaybe = a =>\n b => a.Nothing\n ? b\n : b.Nothing\n ? a\n : Just(\n mappend(a.Just)(b.Just)\n );",
"mappendOrd": "// mappendOrd (<>) :: Ordering -> Ordering -> Ordering\nconst mappendOrd = x =>\n y => 0 !== x\n ? x\n : y;",
"mappendTuple": "// mappendTuple (<>) :: (a, b) -> (a, b) -> (a, b)\nconst mappendTuple = ([a, b]) =>\n ([c, d]) => Tuple(\n mappend(a)(c)\n )(\n mappend(b)(d)\n );",
"mappendTupleN": "// mappendTupleN (<>) ::\n// (a, b, ...) -> (a, b, ...) -> (a, b, ...)\nconst mappendTupleN = t => t1 => {\n const n = t.length;\n\n return n === t1.length\n ? TupleN(\n [...t].map(\n (x, i) => mappend(x)(t1[i])\n )\n )\n : undefined;\n};",
"matching": "// matching :: [a] -> (a -> Int -> [a] -> Bool)\nconst matching = pat => {\n // A sequence-matching function for findIndices etc\n // findIndices(matching([2, 3]), [1, 2, 3, 1, 2, 3])\n // -> [1, 4]\n const\n n = pat.length,\n bln = 0 < n,\n h = bln\n ? pat[0]\n : undefined;\n\n return x => i => src =>\n bln && h === x && eq(pat)(\n src.slice(i, n + i)\n );\n};",
"matrix": "// matrix Int -> Int -> (Int -> Int -> a) -> [[a]]\nconst matrix = nRows =>\n // A matrix of a given number of columns and rows,\n // in which each value is a given function of its\n // (zero-based) column and row indices.\n nCols => f => Array.from(\n {length: nRows}, (_, iRow) =>\n Array.from(\n {length: nCols},\n (__, iCol) => f(iRow)(iCol)\n )\n );",
"max": "// max :: Ord a => a -> a -> a\nconst max = a =>\n // b if greater than a,\n // otherwise a.\n b => gt(b)(a)\n ? b\n : a;",
"maxBound": "// maxBound :: a -> a\nconst maxBound = x => {\n const e = x.enum;\n\n return Boolean(e)\n ? e[e[x.max]]\n : {\n \"number\": Number.MAX_SAFE_INTEGER,\n \"string\": String.fromCodePoint(0x10FFFF),\n \"boolean\": true\n }[typeof x];\n};",
"maximum": "// maximum :: Ord a => [a] -> a\nconst maximum = xs =>\n // The largest value in a non-empty list.\n 0 < xs.length\n ? xs.slice(1).reduce(\n (a, x) => x > a\n ? x\n : a,\n xs[0]\n )\n : undefined;",
"maximumBy": "// maximumBy :: (a -> a -> Ordering) -> [a] -> a\nconst maximumBy = f =>\n xs => 0 < xs.length\n ? xs.slice(1).reduce(\n (a, x) => 0 < f(x)(a)\n ? x\n : a,\n xs[0]\n )\n : undefined;",
"maximumByMay": "// maximumByMay :: (a -> a -> Ordering) ->\n// [a] -> Maybe a\nconst maximumByMay = f =>\n // Nothing, if the list is empty,\n // or just the maximum value when compared\n // in terms of f.\n xs => 0 < xs.length\n ? Just(xs.slice(1).reduce(\n (a, x) => 0 < f(a)(x)\n ? a\n : x,\n xs[0]\n ))\n : Nothing();",
"maximumMay": "// maximumMay :: Ord a => [a] -> Maybe a\nconst maximumMay = xs =>\n 0 < xs.length\n ? Just(xs.slice(1).reduce(\n (a, x) => x > a\n ? x\n : a,\n xs[0]\n ))\n : Nothing();",
"maximumOn": "// maximumOn :: (Ord b) => (a -> b) -> [a] -> a\nconst maximumOn = f =>\n // The item in xs for which f\n // returns the highest value.\n xs => 0 < xs.length\n ? xs.slice(1).reduce(\n (tpl, x) => {\n const v = f(x);\n\n return v > tpl[1]\n ? Tuple(x)(v)\n : tpl;\n },\n (h => Tuple(h)(f(h)))(xs[0])\n )[0]\n : undefined;",
"maybe": "// maybe :: b -> (a -> b) -> Maybe a -> b\nconst maybe = v =>\n // Default value (v) if m is Nothing, or f(m.Just)\n f => m => \"Just\" in m\n ? f(m.Just)\n : v;",
"mconcatOrd": "// mconcatOrd :: [Ordering] -> Ordering\nconst mconcatOrd = cmps =>\n // A sort compare function derived from\n // a list of such functions, providing\n // for composition of n-ary sorts.\n 0 < cmps.length\n ? foldl(\n mappendOrd\n )(cmps[0])(cmps.slice(1))\n : compare;",
"mean": "// mean :: [Num] -> Num\nconst mean = xs =>\n xs.reduce(\n (a, x) => a + x,\n 0\n ) / xs.length;",
"measuredTree": "// measuredTree :: Tree a ->\n// Tree (a, {leafSum::Int, layerSum::Int,\n// nodeSum::Int, index::Int})\n// eslint-disable-next-line max-lines-per-function\nconst measuredTree = tree => {\n // A tree in which each node is tupled with\n // a (leafSum, layerSum, nodeSum) measure of its sub-tree,\n // where leafSum is the number of descendant leaves,\n // and layerSum is the number of descendant levels,\n // and nodeSum counts all nodes, including the root.\n // Index is a position in a zero-based top-down\n // left to right series.\n // For additional parent indices, see parentIndexedTree.\n const whni = (leafSum, layerSum, nodeSum, ndx) => ({\n leafSum,\n layerSum,\n nodeSum,\n index : ndx\n });\n let i = 0;\n\n return foldTree(\n x => {\n // eslint-disable-next-line no-plusplus\n const topDown = i++;\n\n return xs => Node(\n Tuple(x)(\n 0 < xs.length\n ? (() => {\n const dct = xs.reduce(\n (a, node) => {\n const dimns = node.root[1];\n\n return whni(\n a.leafSum + dimns.leafSum,\n Math.max(a.layerSum)(\n dimns.layerSum\n ),\n a.nodeSum + dimns.nodeSum,\n topDown\n );\n }, whni(0, 0, 0, topDown)\n );\n\n return whni(\n dct.leafSum,\n 1 + dct.layerSum,\n 1 + dct.nodeSum,\n topDown\n );\n })()\n : whni(1, 0, 1, topDown)\n )\n )(xs);\n }\n )(tree);\n};",
"member": "// member :: Key -> Dict -> Bool\nconst member = k =>\n // True if dict contains the key k.\n dict => k in dict;",
"mempty": "// mempty :: a -> a\nconst mempty = v => {\n const t = typeName(v);\n\n return ({\n \"List\": () => [],\n \"Maybe\": () => Nothing(),\n \"Num\": () => 0,\n \"String\": () => \"\",\n \"Tuple\": () => Tuple(\n mempty(v[0])\n )(\n mempty(v[1])\n ),\n \"Node\": () => Node(mempty(root(v)))([])\n })[t]();\n};",
"merge": "// merge :: Ord a => [a] -> [a] -> [a]\nconst merge = xs =>\n // An ordered list derived by merging\n // two other ordered lists.\n mergeBy(compare)(xs);",
"mergeBy": "// mergeBy :: (a -> a -> Ordering) -> [a] -> [a] -> [a]\nconst mergeBy = f =>\n// A single list defined by the ordered\n// merging of xs and ys in terms of the\n// given comparator function.\n xs => ys => {\n const go = (as, bs) =>\n 0 < bs.length\n ? 0 < as.length\n ? 1 !== f(as[0])(bs[0])\n ? [as[0]].concat(\n go(as.slice(1), bs)\n )\n : [bs[0]].concat(\n go(as, bs.slice(1))\n )\n : bs\n : as;\n\n return [].concat(...go(xs, ys));\n };",
"min": "// min :: Ord a => a -> a -> a\nconst min = a =>\n b => b < a\n ? b\n : a;",
"minBound": "// minBound :: a -> a\nconst minBound = x => {\n const e = x.enum;\n\n return Boolean(e)\n ? e[e[0]]\n : {\n \"number\": Number.MIN_SAFE_INTEGER,\n \"string\": String.fromCodePoint(0),\n \"boolean\": false\n }[typeof x];\n};",
"minimum": "// minimum :: Ord a => [a] -> a\nconst minimum = xs =>\n // The least value of xs.\n 0 < xs.length\n ? xs.slice(1).reduce(\n (a, x) => x < a\n ? x\n : a,\n xs[0]\n )\n : null;",
"minimumBy": "// minimumBy :: (a -> a -> Ordering) -> [a] -> a\nconst minimumBy = f =>\n xs => 0 < xs.length\n ? xs.slice(1).reduce(\n (a, x) => 0 > f(x)(a)\n ? x\n : a,\n xs[0]\n )\n : undefined;",
"minimumByMay": "// minimumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a\nconst minimumByMay = f =>\n xs => xs.reduce(\n (a, x) => a.Nothing\n ? Just(x)\n : f(x)(a.Just) < 0\n ? Just(x)\n : a,\n Nothing()\n );",
"minimumMay": "// minimumMay :: [a] -> Maybe a\nconst minimumMay = xs =>\n 0 < xs.length\n ? Just(xs.slice(1).reduce(\n (a, x) => x < a\n ? x\n : a,\n xs[0]\n ))\n : Nothing();",
"minimumOn": "// minimumOn :: (Ord b) => (a -> b) -> [a] -> a\nconst minimumOn = f =>\n // The item in xs for which f\n // returns the highest value.\n xs => 0 < xs.length\n ? xs.slice(1).reduce(\n (tpl, x) => {\n const v = f(x);\n\n return v < tpl[1]\n ? Tuple(x)(v)\n : tpl;\n },\n (h => Tuple(h)(f(h)))(xs[0])\n )[0]\n : undefined;",
"mod": "// mod :: Int -> Int -> Int\nconst mod = n =>\n // Inherits the sign of the *divisor* for non zero\n // results. Compare with `rem`, which inherits\n // the sign of the *dividend*.\n d => (n % d) + (\n signum(n) === signum(-d)\n ? d\n : 0\n );",
"modificationTime": "// modificationTime :: FilePath -> Either String Date\nconst modificationTime = fp =>\n bindLR(fileStatus(fp))(\n dct => Right(ObjC.unwrap(dct.NSFileModificationDate))\n );",
"mul": "// mul (*) :: Num a => a -> a -> a\nconst mul = a =>\n b => a * b;",
"ne": "// ne :: a -> a -> Bool\nconst ne = a =>\n b => a !== b;",
"negate": "// negate :: Num -> Num\nconst negate = n =>\n -n;",
"nest": "// nest :: Tree a -> [a]\nconst nest = tree => {\n // Allowing for lazy (on-demand) evaluation.\n // If the nest turns out to be a function –\n // rather than a list – that function is applied\n // here to the root, and returns a list.\n const xs = tree.nest;\n\n return \"function\" !== typeof xs\n ? xs\n : xs(root(tree));\n};",
"newUUID": "// newUUID :: () -> IO UUID String\nconst newUUID = () =>\n ObjC.unwrap($.NSUUID.UUID.UUIDString);",
"not": "// not :: Bool -> Bool\nconst not = b =>\n !b;",
"notElem": "// notElem :: Eq a => a -> [a] -> Bool\nconst notElem = x =>\n xs => !xs.includes(x);",
"nub": "// nub :: Eq a => [a] -> [a]\nconst nub = xs =>\n [...new Set(xs)];",
"nubBy": "// nubBy :: (a -> a -> Bool) -> [a] -> [a]\nconst nubBy = pEq =>\n // A sublist of xs from which all duplicates,\n // (as defined by the equality predicate pEq)\n // are excluded.\n xs => xs.reduce(\n (seen, x) => seen.some(pEq(x))\n ? seen\n : seen.concat([x]),\n []\n );",
"odd": "// odd :: Int -> Bool\nconst odd = n =>\n !even(n);",
"on": "// on :: (b -> b -> c) -> (a -> b) -> a -> a -> c\nconst on = f =>\n // e.g. groupBy(on(eq)(length))\n g => a => b => f(g(a))(g(b));",
"or": "// or :: [Bool] -> Bool\nconst or = xs =>\n xs.some(Boolean);",
"ord": "// ord :: Char -> Int\nconst ord = c =>\n // Unicode ordinal value of the character.\n c.codePointAt(0);",
"outdented": "// outdented :: String -> String\nconst outdented = s => {\n // All lines in the string outdented by the same amount\n // (just enough to ensure that the least indented lines\n // have no remaining indent)\n // All relative indents are left unchanged\n const\n // Leading indentation characters.\n rgx = /^\\s*/u,\n xs = lines(s),\n n = Math.min(\n ...xs.map(txt => rgx.exec(txt)[0].length)\n );\n\n return 0 < n ? (\n xs.map(x => x.slice(n)).join(\"\\n\")\n ) : s.slice(0);\n};",
"parentIndexedTree": "// parentIndexedTree :: Tree (a, {...index :: Int}) ->\n// Tree (a, {...index :: Int, parent :: Maybe Int})\nconst parentIndexedTree = tree => {\n // A tree additionally decorated with parent indices,\n // derived from a measured tree already decorated with\n // node indices. (See measuredTree).\n const go = mb => node => {\n const\n x = root(node),\n measures = x[1];\n\n return Node(\n Tuple(x[0])({\n ...measures,\n parent: mb\n })\n )(nest(node).map(go(Just(measures.index))));\n };\n\n return go(Nothing())(tree);\n};",
"partition": "// partition :: (a -> Bool) -> [a] -> ([a], [a])\nconst partition = p =>\n // A tuple of two lists - those elements in\n // xs which match p, and those which do not.\n xs => [...xs].reduce(\n (a, x) => (\n p(x)\n ? first\n : second\n )(ys => [...ys, x])(a),\n Tuple([])([])\n );",
"partitionEithers": "// partitionEithers :: [Either a b] -> ([a],[b])\nconst partitionEithers = xs =>\n // A tuple of two lists:\n // first all the Left values in xs,\n // and then all the Right values in xs.\n xs.reduce(\n (a, x) => (\n \"Left\" in x\n ? first(ys => [...ys, x.Left])\n : second(ys => [...ys, x.Right])\n )(a),\n Tuple([])([])\n );",
"partitionTree": "// partitionTree :: (a -> Bool) -> \n// Tree a -> ([Tree a], [Tree a])\nconst partitionTree = p =>\n // A list of matching subtrees, tupled with a list \n // which contains the unmatched residue, if any, \n // of the input tree.\n foldTree(x => vs => {\n const\n [matches, residues] = [...unzip(vs)].map(\n v => v.flat()\n ),\n subTree = Node(x)(residues);\n\n return p(x)\n ? Tuple([subTree, ...matches])([])\n : Tuple(matches)([subTree]);\n });",
"pathAccessor": "// pathAccessor :: String -> Dict -> a\nconst pathAccessor = path =>\n // Value if any, at supplied dot path in object.\n // Null if no such path is found.\n obj => path.split(\".\").reduce(\n (v, k) => v instanceof Object\n ? k in v\n ? v[k]\n : undefined\n : v,\n obj\n );",
"permutations": "// permutations :: [a] -> [[a]]\nconst permutations = xs =>\n // All possible orderings of the items in xs.\n // N factorial permutations, where N === length(xs).\n xs.reduceRight(\n (orderings, x) => orderings.flatMap(\n ordering => Array.from({\n length: 1 + ordering.length\n }, (_, i) => i)\n // One additional permutation for each\n // possible position of x in each\n // existing permutation.\n .map(position => [\n ...ordering.slice(0, position),\n x,\n ...ordering.slice(position)\n ])\n ), [\n []\n ]\n );",
"pi": "// pi :: Float\nconst pi = Math.PI;",
"plural": "// plural :: Int -> String -> String\nconst plural = n =>\n // Singular or plural EN inflection\n // of a given word, preceded by digits.\n k => 1 === n\n ? `${k}`\n : `${k}s`;",
"plus": "// plus :: Num -> Num -> Num\nconst plus = a =>\n // The sum of a and b.\n b => a + b;",
"postorder": "// postorder :: Tree a -> [a]\nconst postorder = t => {\n // List of root elements of tree flattened\n // bottom-up into a postorder list.\n const go = (xs, x) =>\n nest(x).reduce(go, xs)\n .concat(root(x));\n\n return go([], t);\n};",
"pred": "// pred :: Enum a => a -> a\nconst pred = x => {\n const t = typeof x;\n\n return \"number\" !== t ? (() => {\n const [i, mn] = [x, minBound(x)].map(fromEnum);\n\n return i > mn ? (\n toEnum(x)(i - 1)\n ) : Error(\"succ :: enum out of range.\");\n })() : x > Number.MIN_SAFE_INTEGER ? (\n x - 1\n ) : Error(\"succ :: Num out of range.\");\n};",
"predMay": "// predMay :: Enum a => a -> Maybe a\nconst predMay = x => {\n const t = typeof x;\n\n return \"number\" !== t ? (() => {\n const [i, mn] = [x, minBound(x)].map(fromEnum);\n\n return i > mn ? (\n Just(toEnum(x)(i - 1))\n ) : Nothing();\n })() : x > Number.MIN_SAFE_INTEGER ? (\n Just(x - 1)\n ) : Nothing();\n};",
"prependToAll": "// prependToAll :: a -> [a] -> [a]\nconst prependToAll = sep =>\n // prependToAll(0)([1,2,3]) -> [0, 1, 0, 2, 0, 3]\n xs => 0 < xs.length ? [\n sep, xs[0],\n ...prependToAll(sep)(xs.slice(1))\n ] : [];",
"product": "// product :: [Num] -> Num\nconst product = xs =>\n xs.reduce((a, x) => a * x, 1);",
"properFracRatio": "// properFracRatio :: Ratio -> (Int, Ratio)\nconst properFracRatio = nd => {\n const [q, r] = quotRem(nd.n)(nd.d);\n\n return Tuple(q)(Ratio(r)(nd.d));\n};",
"properFraction": "// properFraction :: Real -> (Int, Real)\nconst properFraction = n => {\n const i = Math.floor(n) + (n < 0 ? 1 : 0);\n\n return Tuple(i)(n - i);\n};",
"prunedForest": "// prunedForest (a -> Bool) -> Forest a -> Forest a\nconst prunedForest = p => {\n // A forest of trees in which every node matches p.\n // That is, a forest including only nodes which:\n // 1. match the predicate p, AND\n // 2. descend from ancestors which all match p.\n const\n go = trees => trees.flatMap(tree => {\n const x = root(tree);\n\n return p(x)\n ? [\n Node(x)(\n go(nest(tree))\n )\n ]\n : [];\n });\n\n return go;\n};",
"pureLR": "// pureLR :: a -> Either e a\nconst pureLR = x =>\n // The value x lifted into the Either monad.\n Right(x);",
"pureList": "// pureList :: a -> [a]\nconst pureList = x =>\n [x];",
"pureMay": "// pureMay :: a -> Maybe a\nconst pureMay = x =>\n Just(x);",
"pureT": "// pureT :: String -> (a -> f a)\nconst pureT = t =>\n // Given a type name string, returns a\n // specialised \"pure\", where\n // \"pure\" lifts a value into a particular functor.\n ({\n \"Either\": () => pureLR,\n \"(a -> b)\": () => constant,\n \"Maybe\": () => pureMay,\n \"Node\": () => pureTree,\n \"Tuple\": () => pureTuple,\n \"List\": () => pureList\n })[t || \"List\"]();",
"pureTree": "// pureTree :: a -> Tree a\nconst pureTree = x =>\n Node(x)([]);",
"pureTuple": "// pureTuple :: a -> (a, a)\nconst pureTuple = x =>\n Tuple(\"\")(x);",
"pureZL": "// pureZL :: a -> ZipList a\nconst pureZL = x =>\n // A value lifted into a ZipList\n ZipList(repeat(x));",
"quickSort": "// quickSort :: (Ord a) => [a] -> [a]\nconst quickSort = xs =>\n // Included only for comparison with AppleScript\n // sort and sortBy are faster and more flexible\n xs.length > 1 ? (() => {\n const\n h = xs[0],\n lessMore = partition(x => x <= h)(\n xs.slice(1)\n );\n\n return [].concat(...[\n quickSort(lessMore[0]),\n h,\n quickSort(lessMore[1])\n ]);\n })() : xs;",
"quickSortBy": "// quickSortBy :: (a -> a -> Ordering) -> [a] -> [a]\nconst quickSortBy = cmp => {\n // Included only for comparison with AppleScript.\n // sort and sortBy are faster and more flexible.\n const go = xs => xs.length > 1 ? (() => {\n const\n h = xs[0],\n lessMore = partition(\n x => 1 !== cmp(x)(h)\n )(xs.slice(1));\n\n return [].concat(...[\n go(lessMore[0]),\n h,\n go(lessMore[1])\n ]);\n })() : xs;\n\n return go;\n};",
"quot": "// quot :: Integral a => a -> a -> a\nconst quot = n =>\n m => [n, m].some(isBigInt) ? (\n BigInt(n) / BigInt(m)\n ) : Math.trunc(n / m);",
"quotRem": "// quotRem :: Integral a => a -> a -> (a, a)\nconst quotRem = m =>\n // The quotient, tupled with the remainder.\n n => Tuple(\n Math.trunc(m / n)\n )(\n m % n\n );",
"quoted": "// quoted :: Char -> String -> String\nconst quoted = c =>\n // A string flanked on both sides\n // by a specified quote character.\n s => c + s + c;",
"radians": "// radians :: Float x => Degrees x -> Radians x\nconst radians = x =>\n (Math.PI / 180) * x;",
"raise": "// raise :: Num -> Int -> Num\nconst raise = x =>\n // X to the power of n.\n n => x ** n;",
"randomRInt": "// randomRInt :: Int -> Int -> (() -> IO Int)\nconst randomRInt = low =>\n // The return value of randomRInt is itself\n // a function, which, whenever evaluated,\n // yields a a new pseudo-random integer\n // in the range [low..high].\n high => () => low + Math.floor(\n Math.random() * (1 + (high - low))\n );",
"range": "// range :: Ix a => (a, a) -> [a]\nconst range = (...args) => {\n // The list of values in the subrange defined by a bounding pair.\n // range([0, 2]) -> [0,1,2]\n // range([[0,0], [2,2]])\n // -> [[0,0],[0,1],[0,2],[1,0],[1,1],[1,2],[2,0],[2,1],[2,2]]\n // range([[0,0,0],[1,1,1]])\n // -> [[0,0,0],[0,0,1],[0,1,0],[0,1,1],[1,0,0],[1,0,1],[1,1,0],[1,1,1]]\n const\n ab = 1 !== args.length\n ? args\n : args[0],\n [as, bs] = [ab[0], ab[1]].map(\n x => Array.isArray(x)\n ? x\n : (undefined !== x.type) && (\n x.type.startsWith(\"Tuple\")\n )\n ? listFromTuple(x)\n : [x]\n ),\n an = as.length;\n\n return (an === bs.length)\n ? 1 < an\n ? traverseList(x => x)(\n as.map(\n (_, i) => enumFromTo(as[i])(bs[i])\n )\n )\n : enumFromTo(as[0])(bs[0])\n : [];\n};",
"ratioDiv": "// ratioDiv :: Rational -> Rational -> Rational\nconst ratioDiv = n1 => n2 => {\n const [r1, r2] = [n1, n2].map(rational);\n\n return Ratio(r1.n * r2.d)(\n r1.d * r2.n\n );\n};",
"ratioMinus": "// ratioMinus :: Rational -> Rational -> Rational\nconst ratioMinus = n1 => n2 => {\n const [r1, r2] = [n1, n2].map(rational);\n const d = lcm(r1.d)(r2.d);\n\n return Ratio(\n (r1.n * (d / r1.d)) - (r2.n * (d / r2.d))\n )(d);\n};",
"ratioMult": "// ratioMult :: Rational -> Rational -> Rational\nconst ratioMult = n1 => n2 => {\n const [r1, r2] = map(rational)(\n [n1, n2]\n );\n\n return ratio(r1.n * r2.n)(\n r1.d * r2.d\n );\n};",
"ratioPlus": "// ratioPlus :: Rational -> Rational -> Rational\nconst ratioPlus = n1 =>\n n2 => {\n const [r1, r2] = [n1, n2].map(rational);\n const d = lcm(r1.d)(r2.d);\n\n return ratio(\n (r1.n * (d / r1.d)) + (\n r2.n * (d / r2.d)\n )\n )(d);\n };",
"rational": "// rational :: Num a => a -> Rational\nconst rational = x =>\n isNaN(x)\n ? x\n : Number.isInteger(x)\n ? Ratio(x)(1)\n : approxRatio(undefined)(x);",
"read": "// read :: Read a => String -> a\nconst read = JSON.parse;",
"readFile": "// readFile :: FilePath -> IO String\nconst readFile = fp => {\n // The contents of a text file at the\n // given file path.\n const\n e = $(),\n ns = $.NSString\n .stringWithContentsOfFileEncodingError(\n $(fp).stringByStandardizingPath,\n $.NSUTF8StringEncoding,\n e\n );\n\n return ObjC.unwrap(\n ns.isNil()\n ? e.localizedDescription\n : ns\n );\n};",
"readFileLR": "// readFileLR :: FilePath -> Either String IO String\nconst readFileLR = fp => {\n // Either a message or the contents of any\n // text file at the given filepath.\n const\n uw = ObjC.unwrap,\n e = $(),\n ns = $.NSString\n .stringWithContentsOfFileEncodingError(\n $(fp).stringByStandardizingPath,\n $.NSUTF8StringEncoding,\n e\n );\n\n return ns.isNil()\n ? Left(uw(e.localizedDescription))\n : Right(uw(ns));\n};",
"readHex": "// readHex :: String -> Int\nconst readHex = s =>\n // Integer value of hexadecimal expression.\n parseInt(s, 16);",
"readLR": "// readLR :: Read a => String -> Either String a\nconst readLR = s => {\n try {\n return Right(JSON.parse(s));\n } catch (e) {\n return Left(e.message);\n }\n};",
"readPlistFileLR": "// readPlistFileLR :: FilePath -> Either String Dict\nconst readPlistFileLR = fp =>\n // Either a message or a dictionary of key-value\n // pairs read from the given file path.\n bindLR(\n doesFileExist(fp)\n ? Right(filePath(fp))\n : Left(`No file found at path:\\n\\t${fp}`)\n )(\n fpFull => {\n const\n e = $(),\n maybeDict = $.NSDictionary\n .dictionaryWithContentsOfURLError(\n $.NSURL.fileURLWithPath(fpFull),\n e\n );\n\n return maybeDict.isNil()\n ? (() => {\n const\n msg = ObjC.unwrap(\n e.localizedDescription\n );\n\n return Left(`readPlistFileLR:\\n\\t${msg}`);\n })()\n : Right(ObjC.deepUnwrap(maybeDict));\n }\n );",
"recip": "// recip :: Num -> Num\nconst recip = n =>\n 0 !== n\n ? (1 / n)\n : undefined;",
"recipMay": "// recipMay :: Num -> Maybe Num\nconst recipMay = n =>\n 0 === n ? (\n Nothing()\n ) : Just(1 / n);",
"regexIndexedMatches": "// regexIndexedMatches :: Regex -> String -> [(Int, String)]\nconst regexIndexedMatches = rgx =>\n // (Index, String) tuples for all matches of a\n // regular expression in a given string.\n s => Array.from(\n s.matchAll(rgx),\n m => [m.index, m[0]]\n );",
"regexMatches": "// regexMatches :: Regex String -> String -> [[String]]\nconst regexMatches = rgx =>\n // All matches for the given regular expression\n // in the supplied string s.\n s => [...s.matchAll(new RegExp(rgx, \"gu\"))];",
"rem": "// rem :: Integral a => a -> a -> a\nconst rem = n =>\n // Inherits the sign of the *dividend* for non-zero\n // results. Compare with `mod`, which inherits\n // the sign of the *divisor*.\n m => [n, m].some(isBigInt) ? (\n BigInt(n) % BigInt(m)\n ) : n % m;",
"remQuot": "// remQuot :: Integral a => a -> a -> (a, a)\nconst remQuot = m =>\n // The remainder, tupled with the quotient.\n n => Tuple(\n m % n\n )(\n Math.trunc(m / n)\n );",
"removeFileLR": "// removeFileLR :: FilePath -> Either String String\nconst removeFileLR = fp => {\n const error = $();\n\n return $.NSFileManager.defaultManager\n .removeItemAtPathError(fp, error)\n ? Right(`Removed: ${fp}`)\n : Left(ObjC.unwrap(error.localizedDescription));\n};",
"renamedFile": "// renamedFile :: FilePath -> FilePath ->\n// Either IO String IO String\nconst renamedFile = fp =>\n // Either a message detailing a problem, or\n // confirmation of a filename change in the OS.\n fp1 => {\n const error = $();\n\n return $.NSFileManager.defaultManager\n .moveItemAtPathToPathError(fp, fp1, error)\n ? Right(fp1)\n : Left(\n ObjC.unwrap(error.localizedDescription)\n );\n };",
"repeat": "// repeat :: a -> Generator [a]\nconst repeat = function* (x) {\n while (true) {\n yield x;\n }\n};",
"replace": "// replace :: String -> String -> String -> String\n// replace :: Regex -> String -> String -> String\nconst replace = needle =>\n strNew => strHaystack => strHaystack.replace(\n \"string\" !== typeof needle ? (\n needle\n ) : new RegExp(needle, \"gu\"),\n strNew\n );",
"replicate": "// replicate :: Int -> a -> [a]\nconst replicate = n =>\n // A list of n copies of x.\n x => Array.from({\n length: n\n }, () => x);",
"replicateM": "// replicateM :: Int -> [a] -> [[a]]\nconst replicateM = n =>\n // Instance for lists (arrays) only here.\n xs => {\n const go = x => 0 >= x ? [\n []\n ] : liftA2List(cons)(xs)(\n go(x - 1)\n );\n\n return go(n);\n };",
"replicateString": "// replicateString :: Int -> String -> String\nconst replicateString = n =>\n s => s.repeat(n);",
"require": "// importedFrom :: FilePath -> IO Dict\nconst require = fp =>\n // eslint-disable-next-line no-new-func\n Function(\n readFile(fp)\n )();",
"reverse": "// reverse :: [a] -> [a]\nconst reverse = xs =>\n \"string\" === typeof xs\n ? xs.split(\"\").reverse()\n .join(\"\")\n : xs.slice(0).reverse();",
"rights": "// rights :: [Either a b] -> [b]\nconst rights = xs =>\n xs.flatMap(\n x => (\"Right\" in x) ? [\n x.Right\n ] : []\n );",
"root": "// root :: Tree a -> a\nconst root = tree =>\n // The value attached to a tree node.\n tree.root;",
"rotate": "// rotate :: Int -> [a] -> [a]\nconst rotate = n => xs => {\n // Rightward rotation of xs by n positions.\n const lng = xs.length;\n\n return Infinity > lng ? (\n take(lng)(\n drop(lng - n)(\n cycle(xs)\n )\n )\n ) : undefined;\n};",
"round": "// round :: a -> Int\nconst round = x => {\n const\n nr = properFraction(x),\n [n, r] = [nr[0], nr[1]],\n m = n + (r < 0 ? -1 : 1),\n sign = signum(abs(r) - 0.5);\n\n return (-1 === sign) ? n : (\n 0 === sign ? (even(n) ? n : m) : (\n 1 === sign ? m : undefined\n )\n );\n};",
"roundTo": "// roundTo :: Int -> Float -> Float\nconst roundTo = n => x => {\n const d = 10 ** n;\n\n return Math.round(x * d) / d;\n};",
"runAction": "// runAction :: Action a -> a\nconst runAction = act =>\n // Evaluation of an action.\n act.act(act.arg);",
"safeMay": "// safeMay :: (a -> Bool) -> (a -> b) -> Maybe b\nconst safeMay = p => f => x =>\n p(x) ? Just(f(x)) : Nothing();",
"scanl": "// scanl :: (b -> a -> b) -> b -> [a] -> [b]\nconst scanl = f =>\n // The series of interim values arising\n // from a catamorphism. Parallel to foldl.\n startValue => xs =>\n \"GeneratorFunction\" !== (\n xs.constructor.constructor.name\n )\n ? xs.reduce(\n (a, x) => {\n const v = f(a[0])(x);\n\n return [v, a[1].concat(v)];\n }, [startValue, [startValue]]\n )[1]\n : scanlGen(f)(startValue)(xs);",
"scanl1": "// scanl1 :: (a -> a -> a) -> [a] -> [a]\nconst scanl1 = f =>\n // scanl1 is a variant of scanl that has no\n // starting value argument.\n xs => xs.length > 0 ? (\n scanl(f)(\n xs[0]\n )(xs.slice(1))\n ) : [];",
"scanlGen": "// scanlGen :: (b -> a -> b) -> b -> Gen [a] -> [b]\nconst scanlGen = f =>\n // The series of interim values arising\n // from a catamorphism over an infinite list.\n startValue => function* (gen) {\n let\n a = startValue,\n x = gen.next();\n\n yield a;\n while (!x.done) {\n a = f(a)(x.value);\n yield a;\n x = gen.next();\n }\n };",
"scanr": "// scanr :: (a -> b -> b) -> b -> [a] -> [b]\nconst scanr = f =>\n startValue => xs => xs.reduceRight(\n (a, x) => {\n const v = f(x)(a[0]);\n\n return Tuple(v)([v].concat(a[1]));\n }, Tuple(startValue)([startValue])\n )[1];",
"scanr1": "// scanr1 :: (a -> a -> a) -> [a] -> [a]\nconst scanr1 = f =>\n // scanr1 is a variant of scanr that has no\n // seed-value argument, and assumes that\n // xs is not empty.\n xs => xs.length > 0 ? (\n scanr(f)(\n xs.slice(-1)[0]\n )(xs.slice(0, -1))\n ) : [];",
"second": "// second :: (a -> b) -> ((c, a) -> (c, b))\nconst second = f =>\n // A function over a simple value lifted\n // to a function over a tuple.\n // f (a, b) -> (a, f(b))\n xy => Tuple(\n xy[0]\n )(\n f(xy[1])\n );",
"sequenceA": "// sequenceA :: (Applicative f, Traversable t) => t (f a) -> f (t a)\nconst sequenceA = tfa =>\n traverse(x => x)(\n tfa\n );",
"setCurrentDirectory": "// setCurrentDirectory :: FilePath -> IO ()\nconst setCurrentDirectory = fp =>\n $.NSFileManager.defaultManager\n .changeCurrentDirectoryPath(\n $(fp).stringByStandardizingPath\n );",
"setFromList": "// setFromList :: Ord a => [a] -> Set a\nconst setFromList = xs =>\n new Set(xs);",
"setInsert": "// setInsert :: Ord a => a -> Set a -> Set a\nconst setInsert = x => oSet =>\n oSet.add(x);",
"setMember": "// setMember :: Ord a => a -> Set a -> Bool\nconst setMember = x => oSet =>\n oSet.has(x);",
"setSize": "// setSize :: Set a -> Int\nconst setSize = oSet =>\n oSet.size;",
"shift": "// shift :: Int -> [a] -> [a]\nconst shift = n => xs => {\n const lng = length(xs);\n\n return Infinity > lng ? (\n take(lng)(\n drop(n)(cycle(xs))\n )\n ) : (drop(n)(xs), xs);\n};",
"show": "// show :: a -> String\n// show :: a -> Int -> Indented String\nconst show = x => {\n const\n instances = {\n \"(a -> b)\": () => showFn,\n \"Bool\": () => str,\n \"Bottom\": () => showUndefined,\n \"Date\": () => a => a,\n \"Dict\": () => a => a,\n \"Either\": () => showLR,\n \"List\": () => showList,\n \"Maybe\": () => showMaybe,\n \"Node\": () => a => a,\n \"Num\": () => str,\n \"Ratio\": () => showRatio,\n \"String\": () => str,\n \"Tuple\": () => showTuple\n },\n str = y => y.toString(),\n t = typeName(x);\n\n const instance = instances[\n (/^Tuple/u).test(t) ? (\n \"Tuple\"\n ) : t\n ];\n\n return Boolean(instance) ? (\n JSON.stringify(\n x,\n (_, v) => instance()(v)\n )\n ) : `No Show instance has been defined for ${t}.`;\n};",
"showBinary": "// showBinary :: Int -> String\nconst showBinary = n => {\n const\n binaryChar = m => 0 !== m ? (\n \"1\"\n ) : \"0\";\n\n return showIntAtBase(2)(\n binaryChar\n )(n)(\"\");\n};",
"showDate": "// showDate :: Date -> String\nconst showDate = dte =>\n dte.toJSON;",
"showDict": "// showDict :: Dict -> String\nconst showDict = x =>\n show(x);",
"showFn": "// showFn :: (a -> b) -> String\nconst showFn = f =>\n `λ${f}`;",
"showForest": "// showForest :: [Tree a] -> String\nconst showForest = xs =>\n unlines(xs.map(x => drawTree2(false)(true)(\n fmapTree(show)(\n x\n )\n )));",
"showHex": "// showHex :: Int -> String\nconst showHex = n =>\n // Hexadecimal string for a given integer.\n `0x${n.toString(16)}`;",
"showIntAtBase": "// showIntAtBase :: Int -> (Int -> Char) ->\n// Int -> String -> String\nconst showIntAtBase = base =>\n // A string representation of n, in the given base,\n // using a supplied (Int -> Char) function for\n // digits, and a supplied suffix string.\n toChr => n => rs => {\n const go = ([x, d], r) => {\n const r_ = toChr(d) + r;\n\n return 0 !== x ? (\n go(quotRem(x)(base), r_)\n ) : r_;\n };\n\n const e = \"error: showIntAtBase applied to\";\n\n return 1 >= base ? (\n `${e} unsupported base`\n ) : 0 > n ? (\n `${e} negative number`\n ) : go(quotRem(n)(base), rs);\n };",
"showJSON": "// showJSON :: a -> String\nconst showJSON = x =>\n // Indented JSON representation of the value x.\n JSON.stringify(x, null, 2);",
"showLR": "// showLR :: Either a b -> String\nconst showLR = lr => {\n const k = undefined !== lr.Left ? (\n \"Left\"\n ) : \"Right\";\n\n return `${k}(${unQuoted(show(lr[k]))})`;\n};",
"showList": "// showList :: [a] -> String\nconst showList = xs => {\n const\n s = xs.map(show)\n .join(\", \")\n .replace(/[\\\\\"]/gu, \"\");\n\n return `[${s}]`;\n};",
"showLog": "// showLog :: a -> IO ()\nconst showLog = (...args) =>\n // eslint-disable-next-line no-console\n console.log(\n args\n .map(JSON.stringify)\n .join(\" -> \")\n );",
"showMatrix": "// showMatrix :: (a -> String) -> [[a]] -> String\nconst showMatrix = fShow =>\n rows => Boolean(rows.length) ? (() => {\n const w = fShow(Math.max(...rows.flat())).length;\n\n return rows.map(\n cells => cells.map(\n x => fShow(x).padStart(w, \" \")\n ).join(\" \")\n ).join(\"\\n\");\n })() : \"\";",
"showMaybe": "// showMaybe :: Maybe a -> String\nconst showMaybe = mb =>\n mb.Nothing ? (\n \"Nothing\"\n ) : `Just(${unQuoted(show(mb.Just))})`;",
"showMenuLR": "// showMenuLR :: Bool -> String -> String ->\n// [String] -> String -> Either String [String]\nconst showMenuLR = blnMult =>\n // An optionally multi-choice menu, with\n // a given title and prompt string.\n // Listing the strings in xs, with\n // the string `selected` pre-selected\n // if found in xs.\n menuTitle => prompt => selected => xs =>\n Boolean(xs.length) ? (() => {\n const sa = Object.assign(\n Application(\"System Events\"), {\n includeStandardAdditions: true\n });\n\n sa.activate();\n\n const v = sa.chooseFromList(xs, {\n withTitle: menuTitle,\n withPrompt: prompt,\n defaultItems: xs.includes(selected) ? (\n [selected]\n ) : [xs[0]],\n okButtonName: \"OK\",\n cancelButtonName: \"Cancel\",\n multipleSelectionsAllowed: blnMult,\n emptySelectionAllowed: false\n });\n\n return Array.isArray(v) ? (\n Right(v)\n ) : Left(`User cancelled ${menuTitle} menu.`);\n })() : Left(`${menuTitle}: No items to choose from.`);",
"showOrdering": "// showOrdering :: Ordering -> String\nconst showOrdering = e =>\n 0 < e.value ? (\n \"GT\"\n ) : 0 > e.value ? (\n \"LT\"\n ) : \"EQ\";",
"showOutline": "// showOutline :: Tree String -> String\nconst showOutline = tree => {\n const go = indent => x =>\n unlines(\n [indent + x.root].concat(\n x.nest.flatMap(go(` ${indent}`))\n )\n );\n\n return go(\"\")(tree);\n};",
"showPrecision": "// showPrecision :: Int -> Float -> String\nconst showPrecision = n => x => {\n // A string showing a floating point number\n // at a given degree of precision.\n const d = 10 ** n;\n\n return str(Math.round(d * x) / d);\n};",
"showRatio": "// showRatio :: Ratio -> String\nconst showRatio = r =>\n \"Ratio\" !== r.type\n ? r.toString()\n : r.n.toString() + (\n 1 !== r.d\n ? `/${r.d}`\n : \"\"\n );",
"showSet": "// showSet :: Set a -> String\nconst showSet = oSet => {\n const\n s = Array.from(oSet)\n .map(x => x.toString())\n .join(\",\");\n\n return `{${s}}`;\n};",
"showTree": "// showTree :: Tree a -> String\nconst showTree = x =>\n drawTree(\n fmapTree(show)(x)\n );",
"showTuple": "// showTuple :: Tuple -> String\nconst showTuple = tpl => {\n const\n s = enumFromTo(0)(tpl.length - 1)\n .map(x => unQuoted(show(tpl[x])))\n .join(\",\");\n\n return `(${s})`;\n};",
"showUndefined": "// showUndefined :: () -> String\nconst showUndefined = () =>\n \"(⊥)\";",
"signum": "// signum :: Num -> Num\nconst signum = n =>\n // Sign of a number.\n n.constructor(\n 0 > n\n ? -1\n : 0 < n\n ? 1\n : 0\n );",
"sj": "// sj :: a -> String\nconst sj = (...args) =>\n // Abbreviation of showJSON for quick testing.\n // Default indent size is two, which can be\n // overriden by any integer supplied as the\n // first argument of more than one.\n JSON.stringify.apply(\n null,\n 1 < args.length && !isNaN(args[0])\n ? [args[1], null, args[0]]\n : [args[0], null, 2]\n );",
"snd": "// snd :: (a, b) -> b\nconst snd = tpl =>\n // Second member of a pair.\n tpl[1];",
"snoc": "// snoc :: [a] -> a -> [a]\nconst snoc = xs =>\n // The mirror image of cons\n // A new copy of the given list,\n // with an atom appended at the end.\n x => xs.concat(x);",
"sort": "// sort :: Ord a => [a] -> [a]\nconst sort = xs =>\n // An A-Z sorted copy of xs.\n xs.slice().sort(\n (a, b) => a < b ? (\n -1\n ) : (\n a > b ? (\n 1\n ) : 0\n )\n );",
"sortBy": "// sortBy :: (a -> a -> Ordering) -> [a] -> [a]\nconst sortBy = f =>\n // A copy of xs sorted by the comparator function f.\n xs => [...xs].sort(\n (a, b) => f(a)(b)\n );",
"sortOn": "// sortOn :: Ord b => (a -> b) -> [a] -> [a]\nconst sortOn = f =>\n // Equivalent to sortBy(comparing(f)), but with f(x)\n // evaluated only once for each x in xs.\n // ('Schwartzian' decorate-sort-undecorate).\n xs => sortBy(\n comparing(x => x[0])\n )(\n xs.map(x => [f(x), x])\n )\n .map(x => x[1]);",
"span": "// span :: (a -> Bool) -> [a] -> ([a], [a])\nconst span = p =>\n // Longest prefix of xs consisting of elements which\n // all satisfy p, tupled with the remainder of xs.\n xs => {\n const i = xs.findIndex(x => !p(x));\n\n return -1 !== i\n ? Tuple(\n xs.slice(0, i)\n )(\n xs.slice(i)\n ) : Tuple(xs)([]);\n };",
"splitArrow": "// splitArrow (***) :: (a -> b) -> (c -> d) -> ((a, c) -> (b, d))\nconst splitArrow = f =>\n // The functions f and g combined in a single function\n // from a tuple (x, y) to a tuple of (f(x), g(y))\n // (see bimap)\n g => ([a, b]) => Tuple(\n f(a)\n )(\n g(b)\n );",
"splitAt": "// splitAt :: Int -> [a] -> ([a], [a])\nconst splitAt = n =>\n xs => Tuple(xs.slice(0, n))(\n xs.slice(n)\n );",
"splitBy": "// splitBy :: (a -> a -> Bool) -> [a] -> [[a]]\n// splitBy :: (String -> String -> Bool) ->\n// String -> [String]\nconst splitBy = p =>\n // Splitting not on a delimiter, but wherever the\n // relationship between consecutive terms matches\n // a binary predicate.\n xs => 2 > xs.length\n ? [xs]\n : (() => {\n const\n [h, ...t] = xs,\n ab = t.reduce(\n ([acc, active, prev], x) =>\n p(prev)(x)\n ? [acc.concat([active]), [x], x]\n : [acc, active.concat(x), x],\n [[], [h], h]\n );\n\n return ab[0].concat([ab[1]]);\n })();",
"splitExtension": "// splitExtension :: FilePath -> (String, String)\nconst splitExtension = fp => {\n // The file path split before any extension,\n // or tupled with the empty string, if\n // no extension is seen.\n const\n lastIndex = [...fp].findLastIndex(\n c => \"./\".includes(c)\n );\n\n return (-1 !== lastIndex) && (\".\" === fp[lastIndex])\n ? Tuple(fp.slice(0, lastIndex))(\n fp.slice(lastIndex)\n )\n : Tuple(fp)(\"\");\n};",
"splitFileName": "// splitFileName :: FilePath -> (String, String)\nconst splitFileName = strPath =>\n // Tuple of directory and file name,\n // derived from file path. (Inverse of combine).\n (\"\" !== strPath) ? (\n (\"/\" !== strPath[strPath.length - 1]) ? (() => {\n const\n xs = strPath.split(\"/\"),\n stem = xs.slice(0, -1);\n\n return stem.length > 0 ? (\n Tuple(\n `${stem.join(\"/\")}/`\n )(xs.slice(-1)[0])\n ) : Tuple(\"./\")(xs.slice(-1)[0]);\n })() : Tuple(strPath)(\"\")\n ) : Tuple(\"./\")(\"\");",
"splitOn": "// splitOn :: [a] -> [a] -> [[a]]\n// splitOn :: String -> String -> [String]\nconst splitOn = pat => src =>\n // A list of the strings delimited by\n // instances of a given pattern in s.\n (\"string\" === typeof src) ? (\n src.split(pat)\n ) : (() => {\n const\n lng = pat.length,\n [a, b] = findIndices(matching(pat))(src).reduce(\n ([x, y], i) => Tuple(\n x.concat([src.slice(y, i)])\n )(lng + i),\n Tuple([])(0)\n );\n\n return a.concat([src.slice(b)]);\n })();",
"splitRegex": "// splitRegex :: Regex -> String -> [String]\nconst splitRegex = needle =>\n haystack => haystack.split(needle);",
"sqrt": "// sqrt :: Num -> Num\nconst sqrt = n =>\n 0 <= n\n ? Math.sqrt(n)\n : undefined;",
"sqrtLR": "// sqrtLR :: Num -> Either String Num\nconst sqrtLR = n =>\n 0 > n ? (\n Left(`Square root of negative number: ${n}`)\n ) : Right(Math.sqrt(n));",
"sqrtMay": "// sqrtMay :: Num -> Maybe Num\nconst sqrtMay = n =>\n 0 > n ? (\n Nothing()\n ) : Just(Math.sqrt(n));",
"str": "// str :: a -> String\nconst str = x =>\n Array.isArray(x) && x.every(\n v => (\"string\" === typeof v) && (1 === v.length)\n )\n ? x.join(\"\")\n : null === x\n ? \"null\"\n : x.toString();",
"strip": "// strip :: String -> String\nconst strip = s =>\n s.trim();",
"stripEnd": "// stripEnd :: String -> String\nconst stripEnd = s =>\n s.trimEnd();",
"stripPrefix": "// stripPrefix :: Eq a => [a] -> [a] -> Maybe [a]\nconst stripPrefix = pfx =>\n s => {\n const\n blnString = \"string\" === typeof pfx,\n [vs, ws] = blnString ? (\n [pfx.split(\"\"), s.split(\"\")]\n ) : [pfx, s];\n\n const\n sp_ = (xs, ys) => 0 === xs.length ? (\n Just(blnString ? ys.join(\"\") : ys)\n ) : (0 === ys.length || xs[0] !== ys[0]) ? (\n Nothing()\n ) : sp_(xs.slice(1), ys.slice(1));\n\n return sp_(vs, ws);\n };",
"stripStart": "// stripStart :: String -> String\nconst stripStart = s =>\n s.trimStart();",
"subTreeAtPath": "// subTreeAtPath :: Tree String -> [String] -> Maybe Tree String\nconst subTreeAtPath = tree => path => {\n const go = (subNest, xs) =>\n Boolean(subNest.length) && Boolean(xs.length)\n ? (() => {\n const h = xs[0];\n\n return bindMay(\n find(t => h === t.root)(subNest)\n )(\n t => 1 < xs.length\n ? go(t.nest, xs.slice(1))\n : Just(t)\n );\n })()\n : Nothing();\n\n return go([tree], path);\n};",
"subsequences": "// subsequences :: [a] -> [[a]]\n// subsequences :: String -> [String]\nconst subsequences = qs => {\n // subsequences([1,2,3]) -> [[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]\n // subsequences('abc') -> [\"\",\"a\",\"b\",\"ab\",\"c\",\"ac\",\"bc\",\"abc\"]\n const\n // nonEmptySubsequences :: [a] -> [[a]]\n nonEmptySubsequences = xxs => {\n if (xxs.length < 1) {\n return [];\n }\n const [x, xs] = [xxs[0], xxs.slice(1)];\n const f = (r, ys) => cons(ys)(cons(cons(x)(ys))(r));\n\n return cons([x])(nonEmptySubsequences(xs)\n .reduceRight(f, []));\n };\n\n return (\"string\" === typeof qs) ? (\n cons(\"\")(nonEmptySubsequences(qs.split(\"\"))\n .map(q => \"\".concat(...q)))\n ) : cons([])(nonEmptySubsequences(qs));\n};",
"subsets": "// subsets :: [a] -> [[a]]\nconst subsets = xs => {\n // The list of sublists of xs,\n // including the empty list.\n const go = ys =>\n 0 < ys.length\n ? (() => {\n const\n h = ys[0],\n zs = go(ys.slice(1));\n\n return [\n ...zs.map(z => [h, ...z]),\n ...zs\n ];\n })()\n : [[]];\n\n return go(xs);\n};",
"subtract": "// subtract :: Num -> Num -> Num\nconst subtract = x =>\n y => y - x;",
"succ": "// succ :: Enum a => a -> a\nconst succ = x => {\n const t = typeof x;\n\n return \"number\" !== t ? (\n \"bigint\" !== t ? (\n (() => {\n const [i, mx] = [x, maxBound(x)].map(fromEnum);\n\n return i < mx ? (\n toEnum(x)(1 + i)\n ) : Error(\"succ :: enum out of range.\");\n })()\n ) : BigInt(1) + x\n ) : x < Number.MAX_SAFE_INTEGER ? (\n 1 + x\n ) : Error(\"succ :: Num out of range.\");\n};",
"succMay": "// succMay :: Enum a => a -> Maybe a\nconst succMay = x => {\n const t = typeof x;\n\n return \"number\" !== t ? (() => {\n const [i, mx] = [x, maxBound(x)].map(fromEnum);\n\n return i < mx ? (\n Just(toEnum(x)(1 + i))\n ) : Nothing();\n })() : x < Number.MAX_SAFE_INTEGER ? (\n Just(1 + x)\n ) : Nothing();\n};",
"sum": "// sum :: [Num] -> Num\nconst sum = xs =>\n // The numeric sum of all values in xs.\n xs.reduce((a, x) => a + x, 0);",
"swap": "// swap :: (a, b) -> (b, a)\nconst swap = ab =>\n // The pair ab with its order reversed.\n Tuple(ab[1])(\n ab[0]\n );",
"tail": "// tail :: [a] -> [a]\nconst tail = xs =>\n // A new list consisting of all\n // items of xs except the first.\n \"GeneratorFunction\" !== xs.constructor\n .constructor.name\n ? 0 < xs.length\n ? xs.slice(1)\n : undefined\n : (take(1)(xs), xs);",
"tailMay": "// tailMay :: [a] -> Maybe [a]\nconst tailMay = xs =>\n Boolean(xs.length)\n ? Just(xs.slice(1))\n : Nothing();",
"tails": "// tails :: [a] -> [[a]]\nconst tails = xs =>\n xs.map((_, i) => xs.slice(i))\n .concat([\n []\n ]);",
"take": "// take :: Int -> [a] -> [a]\n// take :: Int -> String -> String\nconst take = n =>\n // The first n elements of a list,\n // string of characters, or stream.\n xs => \"GeneratorFunction\" !== xs\n .constructor.constructor.name\n ? xs.slice(0, n)\n : Array.from({length: n},\n () => {\n const x = xs.next();\n\n return x.done\n ? []\n : [x.value];\n })\n .flat();",
"takeAround": "// takeAround :: (a -> Bool) -> [a] -> [a]\nconst takeAround = p => xs => {\n const ys = takeWhile(p)(xs);\n\n return ys.length < xs.length\n ? ys.concat(takeWhileR(p)(xs))\n : ys;\n};",
"takeBaseName": "// takeBaseName :: FilePath -> String\nconst takeBaseName = fp =>\n // The filename without any extension.\n (\"\" !== fp)\n ? (\"/\" !== fp[fp.length - 1])\n ? (() => {\n const fn = fp.split(\"/\").slice(-1)[0];\n\n return fn.includes(\".\")\n ? fn.split(\".\").slice(0, -1)\n .join(\".\")\n : fn;\n })()\n : \"\"\n : \"\";",
"takeCycle": "// takeCycle :: Int -> [a] -> [a]\nconst takeCycle = n =>\n // First n elements of a non-finite cycle of xs.\n xs => {\n const lng = xs.length;\n\n return (\n n <= lng\n ? xs\n : Array.from(\n {length: n},\n () => xs\n )\n .flat(1)\n )\n .slice(0, n);\n };",
"takeDirectory": "// takeDirectory :: FilePath -> FilePath\nconst takeDirectory = fp =>\n // The directory component of a filepath.\n \"\" !== fp\n ? (() => {\n const xs = fp.split(\"/\").slice(0, -1);\n\n return 0 < xs.length\n ? xs.join(\"/\")\n : \".\";\n })()\n : \".\";",
"takeDropCycle": "// takeDropCycle :: Int -> [a] -> [a]\nconst takeDropCycle = n =>\n // N Members of an infinite cycle of xs, starting from index I\n i => xs => drop(i)(\n take(n + i)(cycle(xs))\n );",
"takeExtension": "// takeExtension :: FilePath -> String\nconst takeExtension = fp => {\n const fn = last(fp.split(\"/\"));\n\n return fn.includes(\".\")\n ? `.${last(fn.split(\".\"))}`\n : \"\";\n};",
"takeFileName": "// takeFileName :: FilePath -> FilePath\nconst takeFileName = fp =>\n // The file name component of a filepath.\n 0 < fp.length\n ? \"/\" !== fp[fp.length - 1]\n ? fp.split(\"/\").slice(-1)[0]\n : \"\"\n : \"\";",
"takeFromThenTo": "// takeFromThenTo :: Int -> Int -> Int -> [a] -> [a]\nconst takeFromThenTo = a =>\n b => z => xs => {\n const ixs = enumFromThenTo(a)(b)(z);\n\n return \"GeneratorFunction\" !== xs.constructor\n .constructor.name\n ? ixs.map(i => xs[i])\n : (() => {\n const g = zipGen(enumFrom(0))(\n take(z)(xs)\n );\n\n return ixs.flatMap(i => {\n const mb = index(g)(i);\n\n return mb.Nothing\n ? []\n : [mb.Just];\n });\n })();\n };",
"takeIterate": "// takeIterate n f x == [x, f x, f (f x), ...]\n// takeIterate :: Int -> (a -> a) -> a -> [a]\nconst takeIterate = n =>\n f => x => Array.from({\n length: n - 1\n }).reduce(\n ([a, vs]) => {\n const v = f(a);\n\n return Tuple(v)(vs.concat(v));\n },\n Tuple(x)([x])\n )[1];",
"takeWhile": "// takeWhile :: (a -> Bool) -> [a] -> [a]\nconst takeWhile = p =>\n // The longest prefix of xs in which\n // all elements satisfy p.\n xs => {\n const i = xs.findIndex(x => !p(x));\n\n return -1 !== i\n ? xs.slice(0, i)\n : xs;\n };",
"takeWhileEnd": "// takeWhileEnd :: (a -> Bool) [a] -> [a]\nconst takeWhileEnd = p =>\n // The longest suffix of xs in which\n // all elements satisfy p.\n xs => xs.slice(\n 1 + xs.findLastIndex(x => !p(x))\n );",
"takeWhileGen": "// takeWhileGen :: (a -> Bool) -> Gen [a] -> [a]\nconst takeWhileGen = p =>\n xs => {\n const ys = [];\n let\n nxt = xs.next(),\n v = nxt.value;\n\n while (!nxt.done && p(v)) {\n ys.push(v);\n nxt = xs.next();\n v = nxt.value;\n }\n\n return ys;\n };",
"takeWhileR": "// takeWhileR :: (a -> Bool) -> [a] -> [a]\nconst takeWhileR = p =>\n // The longest suffix of xs in which\n // all elements satisfy p.\n xs => {\n const i = xs.findLastIndex(x => !p(x));\n\n return -1 !== i\n ? xs.slice(1 + i)\n : [];\n };",
"taskPaperDateString": "// taskPaperDateString :: Date -> String\nconst taskPaperDateString = dte =>\n [...second(t => t.slice(0, 5))(\n iso8601Local(dte).split(\"T\")\n )].join(\" \");",
"taskPaperDayString": "// taskPaperDayString :: Date -> String\nconst taskPaperDayString = dte =>\n taskPaperDateString(dte).slice(0, 10);",
"tempFilePath": "// tempFilePath :: String -> IO FilePath\nconst tempFilePath = template => {\n // File name template to temporary path\n // Random digit sequence inserted between\n // template base and extension\n const\n fldr = ObjC.unwrap($.NSTemporaryDirectory()),\n name = takeBaseName(template),\n xtn = takeExtension(template),\n rnd = Math.random().toString()\n .substring(3);\n\n return `${fldr}${name}${rnd}${xtn}`;\n};",
"toEnum": "// toEnum :: a -> Int -> a\nconst toEnum = e =>\n // The first argument is a sample of the type\n // allowing the function to make the right mapping\n x => ({\n \"number\": Number,\n \"string\": String.fromCodePoint,\n \"boolean\": Boolean,\n \"object\": v => e.min + v\n } [typeof e])(x);",
"toLower": "// toLower :: String -> String\nconst toLower = s =>\n // Lower-case version of string.\n s.toLocaleLowerCase();",
"toRatio": "// toRatio :: Real -> Ratio\nconst toRatio = n =>\n approxRatio(1e-12)(n);",
"toSentence": "// toSentence :: String -> String\nconst toSentence = s =>\n // Sentence case - first character\n // capitalized, and rest lowercase.\n 0 < s.length\n ? s[0].toLocaleUpperCase() + s.slice(1)\n .toLocaleLowerCase()\n : s;",
"toTitle": "// toTitle :: String -> String\nconst toTitle = s =>\n 0 < s.length\n ? `${toUpper(s[0])}${toLower(s.slice(1))}`\n : \"\";",
"toUpper": "// toUpper :: String -> String\nconst toUpper = s =>\n s.toLocaleUpperCase();",
"transpose": "// transpose :: [[a]] -> [[a]]\nconst transpose = rows =>\n // Maximal transpose – the longest row determines\n // the number of columns.\n // If any rows are shorter than those that follow,\n // their elements are skipped:\n // transpose [[10,11],[20],[],[30,31,32]]\n // == [[10,20,30],[11,31],[32]]\n rows.reduce(\n (cols, row) => cols.map((col, i) => {\n const v = row[i];\n\n return undefined !== v\n ? col.concat(v)\n : col;\n }),\n Array.from({\n length: 0 < rows.length\n ? Math.max(...rows.map(x => x.length))\n : 0\n }, () => [])\n );",
"transpose_": "// transpose_ :: [[a]] -> [[a]]\nconst transpose_ = rows =>\n // Minimal transpose – the shortest row\n // limits the number of ouput columns.\n // transpose_([[10, 11], [30, 31, 32]])\n // == [[10, 30], [11, 31]]\n rows.reduce(\n (cols, row) => cols.map(\n (col, i) => col.concat(row[i])\n ),\n Array.from({\n length: 0 < rows.length\n ? Math.min(...rows.map(x => x.length))\n : 0\n }, () => [])\n );",
"traverse": "// traverse :: (Applicative f, Traversable t) ->\n// (a -> f b) -> t a -> f (t b)\nconst traverse = f =>\n // Each element of a structure mapped to an\n // a functor-wrapped value, with evaluation from\n // from left to right, and the results collected\n // in a single instance of the target functor.\n tx => ({\n \"Either\": () => traverseLR,\n \"Maybe\": () => traverseMay,\n \"Node\": () => traverseTree,\n \"Tuple\": () => traverseTuple,\n \"List\": () => traverseList\n })[tx.type || \"List\"]()(f)(tx);",
"traverseLR": "// traverseLR :: Applicative f =>\n// (t -> f b) -> Either a t -> f (Either a b)\nconst traverseLR = f =>\n // instance of Traversable (Either a) where\n // traverse _ (Left x) = pure (Left x)\n // traverse f (Right y) = Right <$> f y\n lr => \"Left\" in lr\n ? [lr]\n : fmap(Right)(\n f(lr.Right)\n );",
"traverseList": "// traverseList :: (Applicative f) => (a -> f b) ->\n// [a] -> f [b]\nconst traverseList = f =>\n // Collected results of mapping each element\n // of a structure to an action, and evaluating\n // these actions from left to right.\n xs => 0 < xs.length\n ? (() => {\n const\n vLast = f(xs.slice(-1)[0]),\n t = typeName(vLast);\n\n return xs.slice(0, -1).reduceRight(\n (ys, x) => liftA2(cons)(f(x))(ys),\n liftA2(cons)(vLast)(pureT(t)([]))\n );\n })() \n : fType(f)([]);",
"traverseListLR": "// traverseListLR (a -> Either b c) ->\n// [a] -> Either b [c]\nconst traverseListLR = flr =>\n // Traverse over [a] with (a -> Either b c)\n // Either Left b or Right [c]\n xs => {\n const n = xs.length;\n\n return 0 < n\n ? until(\n ([i, lr]) => (n === i) || (\"Left\" in lr)\n )(\n ([i, lr]) => {\n // Passing an optional index argument\n // which flr can ignore or use.\n const lrx = flr(xs[i], i);\n\n return [\n 1 + i,\n \"Right\" in lrx\n ? Right(\n lr.Right.concat([\n lrx.Right\n ])\n )\n : lrx\n ];\n }\n )(\n Tuple(0)(Right([]))\n )[1]\n : Right([]);\n };",
"traverseMay": "// traverseMay :: Applicative f => (t -> f a) -> Maybe t -> f (Maybe a)\nconst traverseMay = f => mb =>\n \"Nothing\" in mb ? (\n [mb]\n ) : fmap(Just)(\n f(mb.Just)\n );",
"traverseTree": "// traverseTree :: Applicative f => (a -> f b) ->\n// Tree a -> f (Tree b)\nconst traverseTree = f => {\n // traverse f (Node x ts) =\n // liftA2 Node (f x) (traverse (traverse f) ts)\n const go = tree =>\n liftA2(Node)(f(tree.root))(\n traverseList(go)(\n tree.nest\n )\n );\n\n return go;\n};",
"traverseTuple": "// traverseTuple :: Functor f => (t -> f b) -> (a, t) -> f (a, b)\nconst traverseTuple = f => ([a, b]) =>\n fmap(Tuple(a))(\n f(b)\n );",
"treeFromDict": "// treeFromDict :: String -> Dict -> Tree String\nconst treeFromDict = rootLabel =>\n dict => {\n const go = x =>\n \"object\" !== typeof x\n ? []\n : Array.isArray(x)\n ? x.flatMap(go)\n : keys(x).map(\n k => Node(k)(\n go(x[k])\n )\n );\n\n return Node(rootLabel)(\n go(dict)\n );\n };",
"treeFromJSON": "// treeFromJSON :: JSON String -> Tree a\nconst treeFromJSON = json => {\n // Assumes a recursive [root, nest] JSON format,\n // in which `root` is a parseable value string, and `nest`\n // is a possibly empty list of [`root`, `nest`] pairs.\n const go = ([rootValue, subNest]) =>\n Node(rootValue)(subNest.map(go));\n\n return go(JSON.parse(json));\n};",
"treeFromNestedDict": "// treeFromNestedDict -> Dict -> Either String Tree Dict\nconst treeFromNestedDict = dict => {\n // A generic Tree structure from a dict\n // with keys assumed to include no more than\n // one key to a *list* value,\n // with this pattern applied recursively\n // to each child dictionary in such a list.\n const go = dct => {\n const\n kvs = Object.entries(dct),\n lists = kvs.filter(\n ([_, v]) => Array.isArray(v)\n ),\n lng = lists.length;\n\n return 0 < lng ? (\n 1 < lng ? (() => {\n const\n listing = bulleted(\" \")(\n unlines(lists.map(fst))\n ),\n msg = `Ambiguous structure :: ${lng}` + (\n ` multiple sublists in:\\n${dct.name}`\n );\n\n return Left(`${msg}:\\n${listing}`);\n })() : (() => {\n const [nestName, xs] = lists[0];\n\n return bindLR(traverseList(go)(xs))(\n vs => Right(\n Node({\n ...deleteKey(nestName)(dct),\n \"List title\": nestName\n })(vs)\n )\n );\n })()\n ) : Right(Node(dct)([]));\n };\n\n return go(dict);\n};",
"treeLeaves": "// treeLeaves :: Tree a -> [Tree a]\nconst treeLeaves = tree => {\n const go = t => {\n const xs = nest(t);\n\n return 0 < xs.length\n ? xs.flatMap(go)\n : [t];\n };\n\n return go(tree);\n};",
"treeMatch": "// treeMatch :: (a -> Bool) -> Tree a -> [Tree a]\nconst treeMatch = p => {\n // Either a list containing the the first node\n // in the tree which matches the predicate p,\n // or an empty list if no match is found.\n const go = tree =>\n p(tree.root)\n ? [tree]\n : f(tree.nest);\n\n const f = xs => {\n const n = xs.length;\n\n return until(\n ([i, ms]) => (n === i) || (0 < ms.length)\n )(\n ([i]) => [1 + i, go(xs[i])]\n )(\n [0, []]\n )[1];\n };\n\n return go;\n};",
"treeMatches": "// treeMatches :: (a -> Bool) -> Tree a -> [Tree a]\nconst treeMatches = p => {\n // A list of all nodes in the tree which match\n // a predicate p.\n // For the first matching value only, see findTree.\n // To ignore descendants where an ancestor already matches\n // write just [tree] in lieu of [tree, ...tree.nest.flatMap(go)]\n const go = tree =>\n p(tree.root)\n ? [tree, ...tree.nest.flatMap(go)]\n : tree.nest.flatMap(go);\n\n return go;\n};",
"treeMenu": "// treeMenu :: Tree String -> IO [String]\nconst treeMenu = tree => {\n const go = t => {\n const\n strTitle = t.root,\n subs = t.nest,\n menu = subs.map(root),\n blnMore = 0 < subs.flatMap(nest).length;\n\n return until(tpl => !fst(tpl) || !isNull(snd(tpl)))(\n tpl => either(\n x => Tuple(false)([])\n )(\n Tuple(true)\n )(\n bindLR(\n showMenuLR(!blnMore)(strTitle)(menu)\n )(ks => {\n const\n k = ks[0],\n msg = `${k}: not found in ${ks}`;\n\n return maybe(\n Left(msg)\n )(Right)(\n bindMay(\n find(x => k === x.root)(\n subs\n )\n )(\n chosen => Just(\n isNull(chosen.nest) ? (\n ks\n ) : go(chosen)\n )\n )\n );\n })\n )\n )(Tuple(true)([]))[1];\n };\n\n return go(tree);\n};",
"treeMenuBy": "// treeMenuBy :: (a -> String) Tree a -> IO [a]\nconst treeMenuBy = fNodeKey => {\n const go = tree => {\n const\n strTitle = fNodeKey(tree.root),\n subTrees = nest(tree),\n menu = subTrees.map(\n compose(fNodeKey, root)\n ).sort();\n\n return until(\n ([a, b]) => !a || !isNull(b)\n )(\n () => either(\n x => Tuple(false)([])\n )(\n Tuple(true)\n )(\n bindLR(\n showMenuLR(true)(strTitle)(menu)\n )(\n ks => {\n const\n k0 = ks[0],\n msg = `${k0}: not found in ${ks}`;\n\n return maybe(\n Left(msg)\n )(Right)(\n bindMay(\n find(\n x => k0 === fNodeKey(\n x.root\n )\n )(subTrees)\n )(\n firstChosen => Just(\n isNull(\n nest(firstChosen)\n )\n ? ks.map(\n k => find(\n x => k === fNodeKey(\n x.root\n )\n )(subTrees).Just\n )\n : go(firstChosen)\n )\n )\n );\n }\n )\n )\n )(Tuple(true)([]))[1];\n };\n\n return go;\n};",
"truncate": "// truncate :: Num -> Int\nconst truncate = x =>\n \"Ratio\" === x.type ? (\n properFracRatio(x)[0]\n ) : properFraction(x)[0];",
"tupleFromList": "// tupleFromList :: [a] -> (a, a ...)\nconst tupleFromList = xs =>\n TupleN(...xs);",
"typeName": "// typeName :: a -> String\nconst typeName = v => {\n const t = typeof v;\n\n return \"object\" === t\n ? null !== v\n ? Array.isArray(v)\n ? \"List\"\n : \"Date\" === v.constructor.name\n ? \"Date\"\n : null !== v\n ? (() => {\n const ct = v.type;\n\n return Boolean(ct)\n ? (/Tuple\\d+/u).test(ct)\n ? \"TupleN\"\n : ct\n : \"Dict\";\n })()\n : \"Bottom\"\n : \"Bottom\"\n\n : {\n \"boolean\": \"Bool\",\n \"date\": \"Date\",\n \"number\": \"Num\",\n \"string\": \"String\",\n \"function\": \"(a -> b)\"\n } [t] || \"Bottom\";\n};",
"unDigits": "// unDigits :: [Int] -> Int\nconst unDigits = ds =>\n // The integer with the given digits.\n ds.reduce((a, x) => (10 * a) + x, 0);",
"unQuoted": "// unQuoted :: String -> String\nconst unQuoted = s =>\n 1 < s.length ? (\n q => s.slice(\n q !== s[0] ? 0 : 1,\n q !== s.slice(-1) ? undefined : -1\n )\n )(\n String.fromCodePoint(34)\n ) : s;",
"uncons": "// uncons :: [a] -> Maybe (a, [a])\nconst uncons = xs => {\n // Just a tuple of the head of xs and its tail,\n // Or Nothing if xs is an empty list.\n const n = length(xs);\n\n return 0 < n\n ? Infinity > n\n // Finite list\n ? Just(Tuple(xs[0])(xs.slice(1)))\n\n // Lazy generator\n : (() => {\n const nxt = take(1)(xs);\n\n return 0 < nxt.length\n ? Just(Tuple(nxt[0])(xs))\n : Nothing();\n })()\n : Nothing();\n};",
"uncurry": "// uncurry :: (a -> b -> c) -> ((a, b) -> c)\nconst uncurry = f =>\n // A function over a Tuple or argument pair, \n // derived from a curried function.\n (...args) => {\n const [x, y] = 2 === args.length\n ? args\n : args[0]\n\n return f(x)(y);\n };",
"uncurryN": "// uncurryN :: (a -> b ... -> e) -> (a, b ...) -> e\nconst uncurryN = f =>\n // A function over a tuple of values, \n // derived from a curried function absorbing \n // any number of arguments.\n (...args) => args.reduce(\n (g, x) => g(x),\n f\n );",
"unfoldForest": "// unfoldForest :: (b -> (a, [b])) -> [b] -> [Tree]\nconst unfoldForest = f =>\n // A forest built from a list of seed values.\n xs => xs.map(unfoldTree(f));",
"unfoldTree": "// unfoldTree :: (b -> (a, [b])) -> b -> Tree a\nconst unfoldTree = f =>\n // A tree unfolded in breadth-first order\n // from a seed value.\n // Given a seed value, f defines a tuple:\n // (Node root value, [seed])\n // Empty seed lists conclude recursion.\n b => uncurry(Node)(\n second(unfoldForest(f))(\n f(b)\n )\n );",
"unfoldl": "// unfoldl :: (b -> Maybe (b, a)) -> b -> [a]\nconst unfoldl = f => v => {\n // Dual to reduce or foldl.\n // Where these reduce a list to a summary value, unfoldl\n // builds a list from a seed value.\n // Where f returns Just(a, b), a is appended to the list,\n // and the residual b is used as the argument for the next\n // application of f.\n // Where f returns Nothing, the completed list is returned.\n // unfoldl(x => 0 !== x ? Just([x - 1, x]) : Nothing(), 10);\n // --> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n let\n xr = [v, v],\n xs = [];\n\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const mb = f(xr[0]);\n\n if (mb.Nothing) {\n return xs;\n // eslint-disable-next-line no-else-return\n } else {\n xr = mb.Just;\n xs = [xr[1]].concat(xs);\n }\n }\n};",
"unfoldr": "// unfoldr :: (b -> Maybe (a, b)) -> b -> Gen [a]\nconst unfoldr = f =>\n // A lazy (generator) list unfolded from a seed value\n // by repeated application of f to a value until no\n // residue remains. Dual to fold/reduce.\n // f returns either Nothing or Just (value, residue).\n // For a strict output list,\n // wrap with `list` or Array.from\n x => (\n function* () {\n let maybePair = f(x);\n\n while (!maybePair.Nothing) {\n const valueResidue = maybePair.Just;\n\n yield valueResidue[0];\n maybePair = f(valueResidue[1]);\n }\n }()\n );",
"union": "// union :: [a] -> [a] -> [a]\nconst union = xs => ys =>\n unionBy(a => b => a === b)(xs)(ys);",
"unionBy": "// unionBy :: (a -> a -> Bool) -> [a] -> [a] -> [a]\nconst unionBy = fnEq =>\n // The union of xs and ys in terms of the\n // equality function given in fnEq\n xs => ys => {\n const sx = nubBy(fnEq)(xs);\n\n return sx.concat(\n sx.reduce(\n (a, x) => deleteBy(fnEq)(\n x\n )(a),\n nubBy(fnEq)(ys)\n )\n );\n };",
"unionSet": "// unionSet :: Ord a => Set a -> Set a -> Set a\nconst unionSet = s => s1 =>\n Array.from(s1.values())\n .reduce(\n (a, x) => (a.add(x), a),\n new Set(s)\n );",
"unlines": "// unlines :: [String] -> String\nconst unlines = xs =>\n // A single string formed by the intercalation\n // of a list of strings with the newline character.\n xs.join(\"\\n\");",
"unsnoc": "// unsnoc :: [a] -> Maybe ([a], a)\nconst unsnoc = xs =>\n // Nothing if the list is empty, otherwise\n // Just the init and the last.\n Boolean(xs.length) ? (\n Just(Tuple(xs.slice(0, -1))(xs.slice(-1)[0]))\n ) : Nothing();",
"until": "// until :: (a -> Bool) -> (a -> a) -> a -> a\nconst until = p =>\n // The value resulting from successive applications\n // of f to f(x), starting with a seed value x,\n // and terminating when the result returns true\n // for the predicate p.\n f => x => {\n let v = x;\n\n while (!p(v)) {\n v = f(v);\n }\n\n return v;\n };",
"unwords": "// unwords :: [String] -> String\nconst unwords = xs =>\n // A space-separated string derived\n // from a list of words.\n xs.join(\" \");",
"unwrap": "// unwrap :: NSObject -> a\nconst unwrap = ObjC.unwrap;",
"unzip": "// unzip :: [(a,b)] -> ([a],[b])\nconst unzip = xys =>\n // A list of the first items in each pair\n // of the zip, tupled with a list of all\n // the second items.\n Tuple(\n xys.map(xy => xy[0])\n )(\n xys.map(xy => xy[1])\n );\n",
"unzip3": "// unzip3 :: [(a,b,c)] -> ([a],[b],[c])\nconst unzip3 = xyzs =>\n xyzs.reduce(\n (a, x) => TupleN(...[0, 1, 2].map(\n i => a[i].concat(x[i])\n )),\n TupleN([], [], [])\n );",
"unzip4": "// unzip4 :: [(a,b,c,d)] -> ([a],[b],[c],[d])\nconst unzip4 = wxyzs =>\n wxyzs.reduce(\n (a, x) => TupleN(...[0, 1, 2, 3].map(\n i => a[i].concat(x[i])\n )),\n TupleN([], [], [], [])\n );",
"unzipN": "// unzipN :: [(a,b,...)] -> ([a],[b],...)\nconst unzipN = tpls =>\n TupleN(\n ...tpls.reduce(\n (a, tpl) => a.map(\n (x, i) => x.concat(tpl[i])\n ),\n replicate(\n 0 < tpls.length\n ? tpls[0].length\n : 0, []\n )\n )\n );",
"variance": "// variance :: [Num] -> Num\nconst variance = xs => {\n const\n lng = xs.length,\n avg = xs.reduce((a, b) => a + b, 0) / lng;\n\n return xs.reduce(\n (a, b) => a + ((b - avg) ** 2),\n 0\n ) / (lng - 1);\n};",
"words": "// words :: String -> [String]\nconst words = s =>\n // List of space-delimited sub-strings.\n // Leading and trailling space ignored.\n s.split(/\\s+/u).filter(Boolean);",
"wrap": "// wrap :: a -> NSObject\nconst wrap = ObjC.wrap;",
"writeFile": "// writeFile :: FilePath -> String -> IO ()\nconst writeFile = fp => s =>\n $.NSString.alloc.initWithUTF8String(s)\n .writeToFileAtomicallyEncodingError(\n $(fp)\n .stringByStandardizingPath, false,\n $.NSUTF8StringEncoding, null\n );",
"writeFileLR": "// writeFileLR :: FilePath ->\n// String -> Either String IO FilePath\nconst writeFileLR = fp =>\n // Either a message or the filepath\n // to which the string has been written.\n s => {\n const\n e = $(),\n efp = $(fp).stringByStandardizingPath;\n\n return $.NSString.alloc\n .initWithUTF8String(s)\n .writeToFileAtomicallyEncodingError(\n efp, false,\n $.NSUTF8StringEncoding, e\n )\n ? Right(ObjC.unwrap(efp))\n : Left(ObjC.unwrap(e.localizedDescription));\n };",
"writeTempFile": "// writeTempFile :: String -> String -> IO FilePath\nconst writeTempFile = template =>\n // File name template -> string data -> IO temporary path\n txt => {\n const\n fp = ObjC.unwrap($.NSTemporaryDirectory()) +\n takeBaseName(template) + Math.random()\n .toString()\n .substring(3) + takeExtension(template);\n\n return (writeFile(fp)(txt), fp);\n };",
"zeroPadded": "// zeroPadded :: Int -> Int -> String\nconst zeroPadded = w =>\n // A string representation of the integer n,\n // zero padded at left to width w.\n n => `${n}`.padStart(w, \"0\");",
"zip": "// zip :: [a] -> [b] -> [(a, b)]\nconst zip = xs =>\n // The paired members of xs and ys, up to\n // the length of the shorter of the two lists.\n ys => Array.from({\n length: Math.min(xs.length, ys.length)\n }, (_, i) => [xs[i], ys[i]]);",
"zip3": "// zip3 :: [a] -> [b] -> [c] -> [(a, b, c)]\nconst zip3 = xs =>\n // Triples of the values at each position of\n // xs,ys,zs up to the length of the shortest.\n ys => zs => Array.from(\n {\n length: Math.min(\n ...[xs, ys, zs].map(x => x.length)\n )\n },\n (_, i) => [xs[i], ys[i], zs[i]]\n );",
"zip4": "// zip4 :: [a] -> [b] -> [c] -> [d] -> [(a, b, c, d)]\nconst zip4 = ws =>\n // List of triples of the values at each position\n // of xs,ys,zs up to the length of the shortest.\n xs => ys => zs => Array.from(\n {\n length: Math.min(\n ...[ws, xs, ys, zs].map(x => x.length)\n )\n },\n (_, i) => [ws[i], xs[i], ys[i], zs[i]]\n );",
"zipGen": "// zipGen :: (a -> b -> c) ->\n// Gen [a] -> Gen [b] -> Gen [c]\nconst zipGen = ga =>\n // A composite generator formed by the application\n // of f to each pair of values in a zip of two\n // generators.\n gb => {\n const go = function* (ma, mb) {\n let\n a = ma,\n b = mb;\n\n while (!a.Nothing && !b.Nothing) {\n const [ax, axs] = a.Just;\n const [bx, bxs] = b.Just;\n\n yield [ax, bx];\n a = uncons(axs);\n b = uncons(bxs);\n }\n };\n\n return go(uncons(ga), uncons(gb));\n };",
"zipList": "// zipList :: [a] -> [b] -> [(a, b)]\nconst zipList = xs => ys => {\n const\n n = Math.min(length(xs), length(ys)),\n vs = take(n)(ys);\n\n return take(n)(xs)\n .map((x, i) => Tuple(x)(vs[i]));\n};",
"zipN": "// zipN :: [a] -> [b] -> ... -> [(a, b ...)]\nconst zipN = (...xss) =>\n 0 < xss.length\n ? Array.from(\n { length: Math.min(...xss.map(xs => xs.length)) },\n (_, i) => TupleN(...xss.map(xs => xs[i]))\n )\n : [];",
"zipWith": "// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]\nconst zipWith = f =>\n // A list with the length of the shorter of\n // xs and ys, defined by zipping with a\n // custom function, rather than with the\n // default tuple constructor.\n xs => ys => {\n const n = Math.min(...[xs, ys].map(length));\n\n return Infinity > n\n ? (([as, bs]) => Array.from({\n length: n\n }, (_, i) => f(as[i])(\n bs[i]\n )))([xs, ys].map(\n take(n)\n ))\n : zipWithGen(f)(xs)(ys);\n };",
"zipWith3": "// zipWith3 :: (a -> b -> c -> d) ->\n// [a] -> [b] -> [c] -> [d]\nconst zipWith3 = f =>\n xs => ys => zs => Array.from({\n length: Math.min(\n ...[xs, ys, zs].map(x => x.length)\n )\n }, (_, i) => f(xs[i])(ys[i])(zs[i]));",
"zipWith4": "// zipWith4 :: (a -> b -> c -> d -> e) ->\n// [a] -> [b] -> [c] -> [d] -> [e]\nconst zipWith4 = f =>\n ws => xs => ys => zs => Array.from({\n length: Math.min(\n ...[ws, xs, ys, zs].map(x => x.length)\n )\n }, (_, i) => f(ws[i])(xs[i])(ys[i])(zs[i]));",
"zipWithGen": "// zipWithGen :: (a -> b -> c) ->\n// Gen [a] -> Gen [b] -> Gen [c]\nconst zipWithGen = f =>\n // A composite generator formed by the application\n // of f to each pair of values in a zip of two\n // generators.\n ga => gb => {\n const go = function* (ma, mb) {\n let\n a = ma,\n b = mb;\n\n while (!a.Nothing && !b.Nothing) {\n const [ax, axs] = a.Just;\n const [bx, bxs] = b.Just;\n\n yield f(ax)(bx);\n a = uncons(axs);\n b = uncons(bxs);\n }\n };\n\n return go(uncons(ga), uncons(gb));\n };",
"zipWithList": "// zipWithList :: (a -> b -> c) -> [a] -> [b] -> [c]\nconst zipWithList = f =>\n // A list constructed by zipping with a\n // custom function, rather than with the\n // default tuple constructor.\n xs => ys => ((xs_, ys_) => {\n const lng = Math.min(length(xs_), length(ys_));\n\n return take(lng)(xs_).map(\n (x, i) => f(x)(ys_[i])\n );\n })([...xs], [...ys]);",
"zipWithList_": "// zipWithList_ :: (a -> b -> c) -> [a] -> [b] -> [c]\nconst zipWithList_ = f =>\n // A list constructed by zipping with a\n // custom function, rather than with the\n // default tuple constructor.\n xs => ys => Array.from(\n { length: Math.min(xs.length, ys.length) },\n (_, i) => f(xs[i])(ys[i])\n );",
"zipWithLong": "// zipWithLong :: (a -> a -> a) -> [a] -> [a] -> [a]\nconst zipWithLong = f => {\n // A list with the length of the *longer* of\n // xs and ys, defined by zipping with a\n // custom function, rather than with the\n // default tuple constructor.\n // Any unpaired values, where list lengths differ,\n // are simply appended.\n const go = xs =>\n ys => 0 < xs.length\n ? 0 < ys.length\n ? [f(xs[0])(ys[0])].concat(\n go(\n xs.slice(1)\n )(\n ys.slice(1)\n )\n )\n : xs\n : ys;\n\n return go;\n};",
"zipWithM": "// zipWithM :: Applicative m => (a -> b -> m c) ->\n// [a] -> [b] -> m [c]\nconst zipWithM = f =>\n xs => ys =>\n sequenceA(\n zipWith(f)(\n [...xs]\n )([...ys])\n );",
"zipWithN": "// zipWithN :: (a -> b -> ... -> d) -> [a], [b] ... -> [d]\nconst zipWithN = (f, ...xss) => {\n // Generalisation of ZipWith, ZipWith3 etc.\n // f is a curried function absorbing at least \n // N arguments, where N is the length of xss.\n const m = 0 < xss.length\n ? Math.min(...xss.map(x => x.length))\n : 0;\n\n return xss.reduce(\n (gs, vs) => gs.map((g, i) => g(vs[i])),\n Array.from({ length: m }, () => f)\n );\n};",
"zipWithN_": "// zipWithN_ :: ((a, b ...) -> d) -> [a], [b] ... -> [d]\nconst zipWithN_ = (f, ...xss) =>\n // Generalisation of ZipWith, ZipWith3 etc.\n // f is an uncurried function with arity\n // equal to the length of xss.\n Array.from(\n {\n length: 0 < xss.length\n ? Math.min(...xss.map(x => x.length))\n : 0\n },\n (_, i) => f(\n ...xss.map(xs => xs[i])\n )\n );",
"zipWith_": "// zipWith_ :: (a -> a -> b) -> [a] -> [b]\nconst zipWith_ = f =>\n // A list with the length of the shorter of\n // xs and ys, defined by zipping with a\n // custom function, rather than with the\n // default tuple constructor.\n xs => ys => xs.slice(\n 0, Math.min(xs.length, ys.length)\n )\n .map((x, i) => f(x)(ys[i]));"
}