@thi.ng/lispy 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2025-05-20T19:06:30Z
3
+ - **Last updated**: 2025-05-21T10:56:03Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -11,6 +11,12 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
11
11
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
12
12
  and/or version bumps of transitive dependencies.
13
13
 
14
+ ## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/lispy@0.2.0) (2025-05-21)
15
+
16
+ #### 🚀 Features
17
+
18
+ - add more builtins & control flow ([a3b559c](https://github.com/thi-ng/umbrella/commit/a3b559c))
19
+
14
20
  ## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/lispy@0.1.0) (2025-05-20)
15
21
 
16
22
  #### 🚀 Features
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  [![Mastodon Follow](https://img.shields.io/mastodon/follow/109331703950160316?domain=https%3A%2F%2Fmastodon.thi.ng&style=social)](https://mastodon.thi.ng/@toxi)
8
8
 
9
9
  > [!NOTE]
10
- > This is one of 208 standalone projects, maintained as part
10
+ > This is one of 207 standalone projects, maintained as part
11
11
  > of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
12
12
  > and anti-framework.
13
13
  >
@@ -15,6 +15,22 @@
15
15
  > GitHub](https://github.com/sponsors/postspectacular). Thank you! ❤️
16
16
 
17
17
  - [About](#about)
18
+ - [Core language features](#core-language-features)
19
+ - [Constants](#constants)
20
+ - [Predicates](#predicates)
21
+ - [Basic math ops](#basic-math-ops)
22
+ - [Boolean logic operators](#boolean-logic-operators)
23
+ - [Bitwise operators](#bitwise-operators)
24
+ - [Comparison operators](#comparison-operators)
25
+ - [Constants & functions from JS-native `Math`](#constants--functions-from-js-native-math)
26
+ - [Selected utilities from thi.ng/math package](#selected-utilities-from-thingmath-package)
27
+ - [Functional programming](#functional-programming)
28
+ - [Control flow](#control-flow)
29
+ - [List/array/object processing](#listarrayobject-processing)
30
+ - [String processing](#string-processing)
31
+ - [Regexp](#regexp)
32
+ - [Misc utilities](#misc-utilities)
33
+ - [Extensibility](#extensibility)
18
34
  - [Status](#status)
19
35
  - [Installation](#installation)
20
36
  - [Dependencies](#dependencies)
@@ -27,76 +43,151 @@
27
43
 
28
44
  Lightweight, extensible, interpreted Lisp-style DSL for embedding in other projects.
29
45
 
30
- > [!NOTE] This DSL implementation has been extracted as standalone package from
46
+ > [!NOTE]
47
+ > This DSL implementation has been extracted as standalone package from
31
48
  > existing work/examples bundled in the thi.ng/umbrella monorepo (i.e.
32
49
  > [lispy-repl](https://github.com/thi-ng/umbrella/tree/develop/examples/lispy-repl))
33
50
 
34
- The core language is intentionally kept extremely minimal and currently only
35
- contains the following:
36
-
37
- - basic math ops (multi-arity)
38
- - logic operators (multi-arity)
39
- - `and`
40
- - `or`
41
- - `not`
42
- - bitwise operators
43
- - `<<`
44
- - `>>` / `>>>`
45
- - `bit-and`
46
- - `bit-or`
47
- - `bit-xor`
48
- - `bit-not`
49
- - comparison operators
50
- - constants & functions from JS-native `Math`
51
- - selected utilities from [thi.ng/math](https://thi.ng/math) package
52
- - `HALF_PI`
53
- - `TAU`
54
- - `clamp`: clamp value to interval
55
- - `deg`: convert radians to degrees
56
- - `fit`: fit value from one interval into another
57
- - `mix`: linear interpolation (same as GLSL `mix()`)
58
- - `rad`: convert degrees to radians
59
- - `step`: same as GLSL `step()`
60
- - `smoothstep`: same as GLSL `smoothstep()`
61
- - basic FP programming constructs
62
- - `comp`: functional composition
63
- - `def`: define global symbol
64
- - `defn`: define global function
65
- - `let`: locally scope var bindings/expression
66
- - `partial`: partial application (currying)
67
- - basic list/array processing
68
- - `aget`: get array index
69
- - `aset`: set array index
70
- - `count`: number of items
71
- - `concat`: same as `Array.prototype.concat(...)`
72
- - `filter`: list/array filtering
73
- - `first`: first item of array
74
- - `map`: list/array transformation
75
- - `next`: remaining array items (after first)
76
- - `push`: same as `Array.prototype.push(...)`
77
- - `reduce`: list/array reduction
78
- - string/regexp processing
79
- - `capitalize`
80
- - `lower`
81
- - `upper`
82
- - `pad-left`
83
- - `pad-right`
84
- - `substr`
85
- - `trim`
86
- - `regexp`
87
- - `re-match`
88
- - `re-test`
89
- - `replace`
90
- - misc utilities
91
- - `print`: aka `console.log(...)`
92
- - `env`: JSON stringified version of current root env
51
+ ## Core language features
52
+
53
+ The core language is intentionally kept minimal, aimed at data transformations,
54
+ and currently only contains the following:
55
+
56
+ ### Constants
57
+ - `T`: true
58
+ - `F`: false
59
+ - `null`: null
60
+ - `PI`
61
+ - `HALF_PI`
62
+ - `TAU`
63
+
64
+ ### Predicates
65
+
66
+ - `(zero? x)`: zero check
67
+ - `(nan? x)`: NaN check
68
+ - `(neg? x)`: < 0 check
69
+ - `(null? x)`: Null(ish) check
70
+ - `(pos? x)`: > 0 check
71
+
72
+ ### Basic math ops
73
+
74
+ - `(+ x y...)`
75
+ - `(- x y...)`
76
+ - `(* x y...)`
77
+ - `(/ x y...)`
78
+ - `(inc x)`: increment (+1)
79
+ - `(dec x)`: decrement (-1)
80
+
81
+ ### Boolean logic operators
82
+
83
+ - `(and x y ...)`
84
+ - `(or x y ...)`
85
+ - `(not x)`
86
+
87
+ ### Bitwise operators
88
+
89
+ - `(<< x y)`
90
+ - `(>> x y)`
91
+ - `(>>> x y)`
92
+ - `(bit-and x y)`
93
+ - `(bit-or x y)`
94
+ - `(bit-xor x y)`
95
+ - `(bit-not x)`
96
+
97
+ ### Comparison operators
98
+
99
+ - `(< x y)`
100
+ - `(<= x y)`
101
+ - `(> x y)`
102
+ - `(>= x y)`
103
+ - `(== x y)`
104
+ - `(!= x y)`
105
+
106
+ ### Constants & functions from JS-native `Math`
107
+
108
+ All included...
109
+
110
+ ### Selected utilities from thi.ng/math package
111
+
112
+ - `(clamp x min max)`: clamp value to interval
113
+ - `(deg x)`: convert radians to degrees
114
+ - `(fit x a b c d)`: fit value from interval `[a..b]` into `[c..d]`
115
+ - `(mix a b t)`: linear interpolation (same as GLSL `mix()`)
116
+ - `(rad x)`: convert degrees to radians
117
+ - `(smoothstep e1 e2 x)`: same as GLSL `smoothstep()`
118
+ - `(step edge x)`: same as GLSL `step()`
119
+
120
+ ### Functional programming
121
+
122
+ - `(always ...)`: function which always returns true
123
+ - `(comp f g)`: functional composition
124
+ - `(def name val)`: define global symbol
125
+ - `(defn name (...args) body)`: define global function
126
+ - `(fnull? x fn)`: function which returns `(fn)` if x is nullish
127
+ - `(identity x)`: function which always returns its arg
128
+ - `(never ...)`: function which always returns false
129
+ - `(partial fn arg)`: partial application (currying)
130
+
131
+ ### Control flow
132
+
133
+ - `(env! (sym val ...))`: modify bindings in current env
134
+ - `(if test truthy falsey?)`: conditional with optional false branch
135
+ - `(let (sym val ...) body)`: locally scoped var bindings/expression
136
+ - `(while test body... (recur (...))?)`: loop while test is truthy
137
+ - `(-> ...)`: Clojure-style thread-first S-expression re-writing
138
+ - `(-> a (+ b) (* c))` → `(* (+ a b) c)`
139
+ - `(->> ...)`: Clojure-style thread-last S-expression re-writing
140
+ - `(->> a (+ b) (* c))` → `(* c (+ b a))`
141
+
142
+ ### List/array/object processing
143
+
144
+ - `(get arr index)`: get array/object value at index/key
145
+ - `(set! arr index value)`: set array/object value for index/key
146
+ - `(concat x y ...)`: same as `Array.prototype.concat(...)`
147
+ - `(count x)`: number of items (also for strings)
148
+ - `(filter fn list)`: list/array filtering
149
+ - `(first x)`: first item of array
150
+ - `(map fn list)`: list/array transformation
151
+ - `(next x)`: remaining array items (after first)
152
+ - `(push arr x...)`: same as `Array.prototype.push(...)`
153
+ - `(reduce fn init list)`: list/array reduction
154
+
155
+ ### String processing
156
+
157
+ - `(capitalize x)`
158
+ - `(float x)`: same as `parseFloat(x)`
159
+ - `(int x radix?)`: same as `parseInt(x, radix)`
160
+ - `(join sep arr)`: same as `Array.prototype.join(sep)`
161
+ - `(lower x)`
162
+ - `(pad-left x width fill)`
163
+ - `(pad-right x width fill)`
164
+ - `(str x...)`: coerce values to string, concat results
165
+ - `(substr x from to?)`
166
+ - `(trim x)`
167
+ - `(upper x)`
168
+
169
+ ### Regexp
170
+
171
+ - `(re-match re x)`
172
+ - `(re-test re x)`
173
+ - `(regexp str flags?)`
174
+ - `(replace str regexp replacement)`
175
+
176
+ ### Misc utilities
177
+
178
+ - `(env)`: JSON stringified version of current env
179
+ - `(syms)`: Array of symbol names in current env
180
+ - `(print x...)`: aka `console.log(...)`
181
+
182
+ ## Extensibility
93
183
 
94
184
  The core language can be easily customized/extended by defining new items in the
95
- root environment `ENV` (see example below).
185
+ root environment `ENV` (see example below) or passing a custom environment to
186
+ [`evalSource()`](https://docs.thi.ng/umbrella/lispyfunctions/evalSource.html).
96
187
 
97
188
  ## Status
98
189
 
99
- **ALPHA** - bleeding edge / work-in-progress
190
+ **BETA** - possibly breaking changes forthcoming
100
191
 
101
192
  [Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Blispy%5D+in%3Atitle)
102
193
 
@@ -126,7 +217,7 @@ For Node.js REPL:
126
217
  const lispy = await import("@thi.ng/lispy");
127
218
  ```
128
219
 
129
- Package sizes (brotli'd, pre-treeshake): ESM: 1.50 KB
220
+ Package sizes (brotli'd, pre-treeshake): ESM: 1.92 KB
130
221
 
131
222
  ## Dependencies
132
223
 
@@ -179,28 +270,59 @@ const SRC = `
179
270
  (greetings! name)
180
271
  ;; hello, lispy!
181
272
 
273
+ ;; basic loop w/ local var
274
+ (let (i 0)
275
+ (while (< i 5)
276
+ (print i)
277
+ (env! (i (inc i)))))
278
+ ;; 0
279
+ ;; 1
280
+ ;; 2
281
+ ;; 3
282
+ ;; 4
283
+
284
+ ;; threading/rewriting operators
285
+ (->> name (str "hello, ") (print "result:"))
286
+ ;; result: hello, lispy
287
+
182
288
  ;; print contents of default environment
183
289
  (print (env))
184
290
  `;
185
291
 
292
+ // execute with customized environment
186
293
  evalSource(SRC, {...ENV, name: "lispy"});
187
294
 
188
295
  // output:
189
296
  // 10
190
297
  // 65
191
- // hello, lispy!
192
- //
298
+ // hello, lispy
299
+ // 0
300
+ // 1
301
+ // 2
302
+ // 3
303
+ // 4
304
+ // result: hello, lispy
193
305
  // {
194
306
  // "+": "<function>",
195
307
  // "*": "<function>",
196
308
  // "-": "<function>",
197
309
  // "/": "<function>",
310
+ // "inc": "<function>",
311
+ // "dec": "<function>",
312
+ // "null?": "<function>",
313
+ // "zero?": "<function>",
314
+ // "neg?": "<function>",
315
+ // "pos?": "<function>",
316
+ // "nan?": "<function>",
198
317
  // "=": "<function>",
199
318
  // "!=": "<function>",
200
319
  // "<": "<function>",
201
320
  // "<=": "<function>",
202
321
  // ">=": "<function>",
203
322
  // ">": "<function>",
323
+ // "T": true,
324
+ // "F": false,
325
+ // "null": null,
204
326
  // "and": "<function>",
205
327
  // "or": "<function>",
206
328
  // "not": "<function>",
@@ -263,13 +385,15 @@ evalSource(SRC, {...ENV, name: "lispy"});
263
385
  // "rad": "<function>",
264
386
  // "step": "<function>",
265
387
  // "smoothstep": "<function>",
266
- // "aget": "<function>",
267
- // "aset": "<function>",
388
+ // "get": "<function>",
389
+ // "set!": "<function>",
268
390
  // "push": "<function>",
269
391
  // "concat": "<function>",
270
392
  // "count": "<function>",
271
393
  // "first": "<function>",
272
394
  // "next": "<function>",
395
+ // "str": "<function>",
396
+ // "join": "<function>",
273
397
  // "lower": "<function>",
274
398
  // "upper": "<function>",
275
399
  // "capitalize": "<function>",
@@ -281,15 +405,22 @@ evalSource(SRC, {...ENV, name: "lispy"});
281
405
  // "re-test": "<function>",
282
406
  // "re-match": "<function>",
283
407
  // "replace": "<function>",
408
+ // "identity": "<function>",
409
+ // "always": "<function>",
410
+ // "never": "<function>",
411
+ // "int": "<function>",
412
+ // "float": "<function>",
284
413
  // "print": "<function>",
285
- // "env": "<function>",
286
414
  // "partial": "<function>",
287
415
  // "partial2": "<function>",
288
416
  // "comp": "<function>",
289
417
  // "comp2": "<function>",
418
+ // "fnull?": "<function>",
290
419
  // "reduce": "<function>",
291
420
  // "map": "<function>",
292
- // "filter": "<function>"
421
+ // "filter": "<function>",
422
+ // "name": "lispy",
423
+ // "greetings!": "<function>"
293
424
  // }
294
425
  ```
295
426
 
@@ -304,10 +435,10 @@ If this project contributes to an academic publication, please cite it as:
304
435
  title = "@thi.ng/lispy",
305
436
  author = "Karsten Schmidt",
306
437
  note = "https://thi.ng/lispy",
307
- year = 2025
438
+ year = 2023
308
439
  }
309
440
  ```
310
441
 
311
442
  ## License
312
443
 
313
- &copy; 2025 Karsten Schmidt // Apache License 2.0
444
+ &copy; 2023 - 2025 Karsten Schmidt // Apache License 2.0
package/index.d.ts CHANGED
@@ -7,9 +7,9 @@ export type Env = Record<string, any>;
7
7
  */
8
8
  export declare const BUILTINS: import("@thi.ng/defmulti").MultiFn2<ASTNode[], Env, any>;
9
9
  /**
10
- * Root environment bindings. This is the default env used by
11
- * {@link evalExpressions} and can be used to define extensions of the core
12
- * language. Functions defined here can receive any number of arguments.
10
+ * Root environment bindings. This is the default env used by {@link evalSource}
11
+ * and can be used to define extensions of the core language. Functions defined
12
+ * here can receive any number of arguments.
13
13
  */
14
14
  export declare const ENV: Env;
15
15
  /**
package/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { identity, always, never } from "@thi.ng/api/fn";
1
2
  import { isFunction } from "@thi.ng/checks/is-function";
2
3
  import { OPERATORS } from "@thi.ng/compare/ops";
3
4
  import { DEFAULT, defmulti } from "@thi.ng/defmulti";
@@ -33,6 +34,36 @@ const __fnImpl = (args, body, env) => (...xs) => {
33
34
  );
34
35
  return body.reduce((_, x) => interpret(x, $env), void 0);
35
36
  };
37
+ const __threadOp = (fn) => ([_, ...body], env) => {
38
+ const n = body.length;
39
+ if (!n) return;
40
+ let res = body[0];
41
+ for (let i = 1; i < n; i++) {
42
+ const curr = { ...body[i] };
43
+ assert(
44
+ curr.type === "expr",
45
+ `expected expression, got ${curr.type}`
46
+ );
47
+ const $curr = curr;
48
+ $curr.children = fn(res, $curr.children);
49
+ res = $curr;
50
+ }
51
+ return interpret(res, env);
52
+ };
53
+ const __injectBindings = (args, env) => {
54
+ const pairs = args.children;
55
+ assert(
56
+ args.type === "expr" && !(pairs.length % 2),
57
+ `require pairs of key-val bindings`
58
+ );
59
+ for (let i = 0, n = pairs.length; i < n; i += 2) {
60
+ assert(
61
+ pairs[i].type === "sym",
62
+ `expected symbol, got: ${pairs[i].type}`
63
+ );
64
+ env[pairs[i].value] = interpret(pairs[i + 1], env);
65
+ }
66
+ };
36
67
  const BUILTINS = defmulti(
37
68
  (x) => x[0].value,
38
69
  {},
@@ -52,22 +83,40 @@ const BUILTINS = defmulti(
52
83
  // create local symbol/variable bindings, e.g.
53
84
  // `(let (a 1 b 2 c (+ a b)) (print a b c))`
54
85
  let: ([_, args, ...body], env) => {
55
- const pairs = args.children;
56
- assert(
57
- args.type === "expr" && !(pairs.length % 2),
58
- `require pairs of key-val bindings`
59
- );
60
- let $env = { ...env };
61
- for (let i = 0, n = pairs.length; i < n; i += 2) {
62
- assert(
63
- pairs[i].type === "sym",
64
- `expected symbol, got: ${pairs[i].type}`
65
- );
66
- $env[pairs[i].value] = interpret(pairs[i + 1], $env);
67
- }
86
+ const $env = { ...env };
87
+ __injectBindings(args, $env);
68
88
  return body.reduce((_2, x) => interpret(x, $env), void 0);
69
89
  },
90
+ while: ([, test, ...body], env) => {
91
+ const n = body.length;
92
+ while (interpret(test, env)) {
93
+ for (let i = 0; i < n; i++) interpret(body[i], env);
94
+ }
95
+ },
96
+ "env!": ([_, args], env) => __injectBindings(args, env),
70
97
  list: ([_, ...body], env) => evalArgs(body, env),
98
+ obj: ([_, ...body], env) => {
99
+ assert(!(body.length % 2), `require pairs of key-val bindings`);
100
+ const obj = {};
101
+ for (let i = 0, n = body.length; i < n; i += 2) {
102
+ const key = body[i].type === "expr" ? interpret(body[i], env) : body[i].value;
103
+ obj[String(key)] = interpret(body[i + 1], env);
104
+ }
105
+ return obj;
106
+ },
107
+ // rewriting operators:
108
+ // iteratively threads first child as FIRST arg of next child
109
+ // (-> a (+ b) (* c)) = (* (+ a b) c)
110
+ "->": __threadOp((res, [f, ...children]) => [f, res, ...children]),
111
+ // iteratively threads first child as LAST arg of next child
112
+ // (->> a (+ b) (* c)) = (* c (+ b a))
113
+ "->>": __threadOp((res, children) => [...children, res]),
114
+ env: (_, env) => JSON.stringify(
115
+ env,
116
+ (_2, val) => isFunction(val) ? "<function>" : val,
117
+ 2
118
+ ),
119
+ syms: (_, env) => Object.keys(env),
71
120
  // add default/fallback implementation to allow calling functions defined in
72
121
  // the environment (either externally or via `defn`)
73
122
  [DEFAULT]: ([x, ...args], env) => {
@@ -88,11 +137,33 @@ const ENV = {
88
137
  "-": __mathOp((acc, x) => acc - x, (x) => -x),
89
138
  // prettier-ignore
90
139
  "/": __mathOp((acc, x) => acc / x, (x) => 1 / x),
140
+ inc: (x) => x + 1,
141
+ dec: (x) => x - 1,
142
+ // predicates
143
+ "null?": (x) => x == null,
144
+ "zero?": (x) => x === 0,
145
+ "neg?": (x) => x < 0,
146
+ "pos?": (x) => x > 0,
147
+ "nan?": (x) => isNaN(x),
91
148
  // comparisons
92
149
  ...OPERATORS,
93
150
  // boolean logic
94
- and: (...args) => args.every((x) => !!x),
95
- or: (...args) => args.some((x) => !!x),
151
+ T: true,
152
+ F: false,
153
+ null: null,
154
+ and: (...args) => {
155
+ let x;
156
+ for (x of args) {
157
+ if (!x) return false;
158
+ }
159
+ return x;
160
+ },
161
+ or: (...args) => {
162
+ for (let x of args) {
163
+ if (x) return x;
164
+ }
165
+ return false;
166
+ },
96
167
  not: (x) => !x,
97
168
  // binary
98
169
  "<<": (x, y) => x << y,
@@ -157,9 +228,9 @@ const ENV = {
157
228
  rad,
158
229
  step,
159
230
  smoothstep: smoothStep,
160
- aget: (arr, i) => arr[i],
161
- aset: (arr, i, x) => arr[i] = x,
162
- push: (list, ...x) => list.push(...x),
231
+ get: (arr, i) => arr[i],
232
+ "set!": (arr, i, x) => arr[i] = x,
233
+ push: (list, ...x) => (list.push(...x), list),
163
234
  concat: (list, ...x) => list.concat(...x),
164
235
  // returns length of first argument (presumably a list or string)
165
236
  // (e.g. `(count "abc")` => 3)
@@ -170,6 +241,8 @@ const ENV = {
170
241
  // there're no further items
171
242
  next: (arg) => arg.length > 1 ? arg.slice(1) : void 0,
172
243
  // strings
244
+ str: (...args) => args.join(""),
245
+ join: (sep, args) => args.join(sep),
173
246
  lower,
174
247
  upper,
175
248
  capitalize,
@@ -181,13 +254,14 @@ const ENV = {
181
254
  "re-test": (regexp, x) => regexp.test(x),
182
255
  "re-match": (regexp, x) => regexp.exec(x),
183
256
  replace: (x, regexp, replacement) => x.replace(regexp, replacement),
257
+ // functions
258
+ identity,
259
+ always,
260
+ never,
261
+ int: parseInt,
262
+ float: parseFloat,
184
263
  // misc
185
- print: console.log,
186
- env: () => JSON.stringify(
187
- ENV,
188
- (_, val) => isFunction(val) ? "<function>" : val,
189
- 2
190
- )
264
+ print: console.log
191
265
  };
192
266
  const evalSource = (src, env = ENV) => parse(src).children.reduce((_, x) => interpret(x, env), void 0);
193
267
  const evalArgs = (nodes, env = ENV) => nodes.map((a) => interpret(a, env));
package/kernel.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const KERNEL = "\n; partial functional application (currying for 1 arg)\n(defn partial (f x) (fn (y) (f x y)))\n\n; partial functional application (currying for 2 args)\n(defn partial2 (f x y) (fn (z) (f x y z)))\n\n; functional composition for 1-arg fns\n(defn comp (f g) (fn (x) (f (g x))))\n\n; functional composition for 2-arg fns\n(defn comp2 (f g) (fn (x y z) (f (g x y) z)))\n\n; list reduction\n(defn reduce (f acc xs) (if xs (reduce f (f acc (first xs)) (next xs)) acc))\n\n; list transformation (expressed as reduction)\n(defn map (f xs) (reduce (fn (acc x) (concat acc (f x))) (list) xs))\n\n; filter list with predicate function\n(defn filter (f xs) (reduce (fn (acc x) (if (f x) (concat acc x) acc)) (list) xs))\n";
1
+ export declare const KERNEL = "\n; partial functional application (currying for 1 arg)\n(defn partial (f x) (fn (y) (f x y)))\n\n; partial functional application (currying for 2 args)\n(defn partial2 (f x y) (fn (z) (f x y z)))\n\n; functional composition for 1-arg fns\n(defn comp (f g) (fn (x) (f (g x))))\n\n; functional composition for 2-arg fns\n(defn comp2 (f g) (fn (x y z) (f (g x y) z)))\n\n; calls f if x is nullish\n(defn fnull? (x f) (if (null? x) (f) x))\n\n; list reduction\n(defn reduce (f acc xs) (if xs (reduce f (f acc (first xs)) (next xs)) acc))\n\n; list transformation (expressed as reduction)\n(defn map (f xs) (reduce (fn (acc x) (concat acc (f x))) (list) xs))\n\n; filter list with predicate function\n(defn filter (f xs) (reduce (fn (acc x) (if (f x) (concat acc x) acc)) (list) xs))\n";
2
2
  //# sourceMappingURL=kernel.d.ts.map
package/kernel.js CHANGED
@@ -11,6 +11,9 @@ const KERNEL = `
11
11
  ; functional composition for 2-arg fns
12
12
  (defn comp2 (f g) (fn (x y z) (f (g x y) z)))
13
13
 
14
+ ; calls f if x is nullish
15
+ (defn fnull? (x f) (if (null? x) (f) x))
16
+
14
17
  ; list reduction
15
18
  (defn reduce (f acc xs) (if xs (reduce f (f acc (first xs)) (next xs)) acc))
16
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/lispy",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Lightweight, extensible, interpreted Lisp-style DSL for embedding in other projects",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -46,7 +46,7 @@
46
46
  "@thi.ng/errors": "^2.5.33",
47
47
  "@thi.ng/math": "^5.11.27",
48
48
  "@thi.ng/object-utils": "^1.1.23",
49
- "@thi.ng/sexpr": "^1.0.16",
49
+ "@thi.ng/sexpr": "^1.0.17",
50
50
  "@thi.ng/strings": "^3.9.12"
51
51
  },
52
52
  "devDependencies": {
@@ -55,6 +55,19 @@
55
55
  "typescript": "^5.8.3"
56
56
  },
57
57
  "keywords": [
58
+ "array",
59
+ "clojure",
60
+ "composition",
61
+ "dsl",
62
+ "functional",
63
+ "interpreter",
64
+ "language",
65
+ "lisp",
66
+ "parser",
67
+ "regexp",
68
+ "runtime",
69
+ "s-expression",
70
+ "string",
58
71
  "typescript"
59
72
  ],
60
73
  "publishConfig": {
@@ -80,8 +93,8 @@
80
93
  }
81
94
  },
82
95
  "thi.ng": {
83
- "status": "alpha",
84
- "year": 2025
96
+ "status": "beta",
97
+ "year": 2023
85
98
  },
86
- "gitHead": "90ae29324123738dde721193785a6743cdf4181e\n"
99
+ "gitHead": "0108278642f57ca9fc7bed0edc967991c20cd594\n"
87
100
  }