klongpy 0.7.0__py3-none-any.whl → 0.7.1__py3-none-any.whl
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.
- klongpy/__init__.py +0 -2
- klongpy/adverbs.py +84 -82
- klongpy/autograd.py +0 -9
- klongpy/backend.py +9 -142
- klongpy/backends/__init__.py +9 -77
- klongpy/backends/base.py +154 -5
- klongpy/backends/numpy_backend.py +2 -1
- klongpy/backends/registry.py +76 -0
- klongpy/backends/torch_backend.py +83 -31
- klongpy/cli.py +50 -7
- klongpy/core.py +113 -1094
- klongpy/db/sys_fn_db.py +3 -3
- klongpy/db/sys_fn_kvs.py +2 -4
- klongpy/dyads.py +203 -162
- klongpy/interpreter.py +32 -15
- klongpy/monads.py +99 -89
- klongpy/parser.py +328 -0
- klongpy/repl.py +2 -2
- klongpy/sys_fn.py +53 -15
- klongpy/sys_fn_ipc.py +4 -9
- klongpy/types.py +503 -0
- klongpy/writer.py +122 -0
- klongpy/ws/sys_fn_ws.py +5 -8
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/METADATA +146 -95
- klongpy-0.7.1.dist-info/RECORD +52 -0
- klongpy-0.7.0.dist-info/RECORD +0 -48
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/WHEEL +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/entry_points.txt +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/licenses/LICENSE +0 -0
- {klongpy-0.7.0.dist-info → klongpy-0.7.1.dist-info}/top_level.txt +0 -0
klongpy/interpreter.py
CHANGED
|
@@ -4,7 +4,6 @@ from collections import deque
|
|
|
4
4
|
from .adverbs import get_adverb_fn
|
|
5
5
|
from .backends import get_backend
|
|
6
6
|
from .core import *
|
|
7
|
-
from .backend import is_number
|
|
8
7
|
from .dyads import create_dyad_functions
|
|
9
8
|
from .monads import create_monad_functions
|
|
10
9
|
from .sys_fn import create_system_functions
|
|
@@ -55,9 +54,10 @@ class KlongContext():
|
|
|
55
54
|
|
|
56
55
|
"""
|
|
57
56
|
|
|
58
|
-
def __init__(self, system_contexts):
|
|
57
|
+
def __init__(self, system_contexts, strict_mode=1):
|
|
59
58
|
self._context = deque([{}, *system_contexts])
|
|
60
59
|
self._min_ctx_count = len(system_contexts)
|
|
60
|
+
self._strict_mode = strict_mode
|
|
61
61
|
|
|
62
62
|
def start_module(self, name):
|
|
63
63
|
self.push(KGModule(name))
|
|
@@ -71,11 +71,28 @@ class KlongContext():
|
|
|
71
71
|
|
|
72
72
|
def __setitem__(self, k, v):
|
|
73
73
|
assert isinstance(k, KGSym)
|
|
74
|
+
|
|
74
75
|
if k not in reserved_fn_symbols:
|
|
76
|
+
# Check if variable exists in any scope
|
|
75
77
|
for d in self._context:
|
|
76
78
|
if in_map(k, d):
|
|
77
79
|
d[k] = v
|
|
78
80
|
return k
|
|
81
|
+
|
|
82
|
+
# Variable doesn't exist - check strict mode
|
|
83
|
+
if self._strict_mode >= 1:
|
|
84
|
+
# Check if we're inside a function (more than just global scope)
|
|
85
|
+
in_function = len(self._context) > self._min_ctx_count + 1
|
|
86
|
+
|
|
87
|
+
if in_function:
|
|
88
|
+
# Inside function - disallow creating new variables
|
|
89
|
+
raise KlongException(
|
|
90
|
+
f"undefined variable: {k}\n"
|
|
91
|
+
f" To create a local variable, declare it in the parameter list: {{[{k}]; ...}}\n"
|
|
92
|
+
f" To modify an existing global, ensure it exists before calling the function"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Create new variable in current scope
|
|
79
96
|
set_context_var(self._context[0], k, v)
|
|
80
97
|
return k
|
|
81
98
|
|
|
@@ -221,14 +238,14 @@ class KlongInterpreter():
|
|
|
221
238
|
Parameters
|
|
222
239
|
----------
|
|
223
240
|
backend : str, optional
|
|
224
|
-
Backend name ('numpy' or 'torch').
|
|
225
|
-
backend (numpy, unless KLONGPY_BACKEND or USE_TORCH env vars are set).
|
|
241
|
+
Backend name ('numpy' or 'torch'). Defaults to 'numpy'.
|
|
226
242
|
device : str, optional
|
|
227
243
|
Device for torch backend ('cpu', 'cuda', 'mps'). Only applies
|
|
228
244
|
when backend='torch'. If None, auto-selects best available device.
|
|
229
245
|
"""
|
|
230
246
|
self._backend = get_backend(backend, device=device)
|
|
231
|
-
|
|
247
|
+
strict_mode = 0 # 0=unsafe (default for backward compat), 1=strict, 2=pedantic
|
|
248
|
+
self._context = KlongContext(create_system_contexts(), strict_mode=strict_mode)
|
|
232
249
|
self._vd = create_dyad_functions(self)
|
|
233
250
|
self._vm = create_monad_functions(self)
|
|
234
251
|
self._start_time = time.time()
|
|
@@ -332,7 +349,7 @@ class KlongInterpreter():
|
|
|
332
349
|
return i+1,arr
|
|
333
350
|
k = i
|
|
334
351
|
while True:
|
|
335
|
-
ii,c = kg_read(t,i,ignore_newline=True,module=self.current_module())
|
|
352
|
+
ii,c = kg_read(t, i, ignore_newline=True, module=self.current_module())
|
|
336
353
|
if safe_eq(c, ';'):
|
|
337
354
|
i = ii
|
|
338
355
|
if k == i - 1:
|
|
@@ -380,7 +397,7 @@ class KlongInterpreter():
|
|
|
380
397
|
| V P
|
|
381
398
|
|
|
382
399
|
"""
|
|
383
|
-
i,a =
|
|
400
|
+
i,a = kg_read_array(t, i, self._backend, ignore_newline=ignore_newline, module=self.current_module())
|
|
384
401
|
if a is None:
|
|
385
402
|
return i,a
|
|
386
403
|
if safe_eq(a, '{'): # read fn
|
|
@@ -597,14 +614,14 @@ class KlongInterpreter():
|
|
|
597
614
|
ctx = {} if f_args is None else {reserved_fn_symbol_map[p]: self.call(q) for p,q in zip(reserved_fn_args,f_args)}
|
|
598
615
|
|
|
599
616
|
if is_list(f) and len(f) > 1 and is_list(f[0]) and len(f[0]) > 0:
|
|
600
|
-
|
|
601
|
-
for q in f[0]
|
|
602
|
-
|
|
603
|
-
have_locals = False
|
|
604
|
-
break
|
|
617
|
+
# Filter out semicolons and check if all remaining elements are symbols
|
|
618
|
+
params = [q for q in f[0] if isinstance(q, KGSym)]
|
|
619
|
+
have_locals = len(params) > 0 and all(isinstance(q, KGSym) for q in params)
|
|
605
620
|
if have_locals:
|
|
606
|
-
for q in
|
|
607
|
-
|
|
621
|
+
for q in params:
|
|
622
|
+
# Don't overwrite function parameters (x, y, z)
|
|
623
|
+
if q not in ctx:
|
|
624
|
+
ctx[q] = q
|
|
608
625
|
f = f[1:]
|
|
609
626
|
|
|
610
627
|
ctx[reserved_dot_f_symbol] = f
|
|
@@ -654,7 +671,7 @@ class KlongInterpreter():
|
|
|
654
671
|
return self._eval_fn(x)
|
|
655
672
|
elif isinstance(x, KGCond):
|
|
656
673
|
q = self.call(x[0])
|
|
657
|
-
p = not ((is_number(q) and q == 0) or is_empty(q))
|
|
674
|
+
p = not ((self._backend.is_number(q) and q == 0) or is_empty(q))
|
|
658
675
|
return self.call(x[1]) if p else self.call(x[2])
|
|
659
676
|
elif isinstance(x,list) and len(x) > 0:
|
|
660
677
|
return [self.call(y) for y in x][-1]
|
klongpy/monads.py
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
from .core import *
|
|
2
2
|
from .autograd import grad_of_fn
|
|
3
|
-
|
|
4
|
-
kg_asarray, is_integer, is_number, str_to_chr_arr, kg_argsort, array_size, vec_fn
|
|
5
|
-
)
|
|
6
|
-
import sys
|
|
3
|
+
|
|
7
4
|
|
|
8
5
|
def eval_monad_atom(a):
|
|
9
6
|
"""
|
|
@@ -22,7 +19,7 @@ def eval_monad_atom(a):
|
|
|
22
19
|
return kg_truth(is_atom(a))
|
|
23
20
|
|
|
24
21
|
|
|
25
|
-
def eval_monad_char(a):
|
|
22
|
+
def eval_monad_char(a, backend):
|
|
26
23
|
"""
|
|
27
24
|
|
|
28
25
|
:#a [Char]
|
|
@@ -35,10 +32,10 @@ def eval_monad_char(a):
|
|
|
35
32
|
:#10 --> :"newline character"
|
|
36
33
|
|
|
37
34
|
"""
|
|
38
|
-
return rec_fn(a, lambda x: KGChar(chr(x))) if is_list(a) else KGChar(chr(a))
|
|
35
|
+
return backend.rec_fn(a, lambda x: KGChar(chr(x))) if is_list(a) else KGChar(chr(a))
|
|
39
36
|
|
|
40
37
|
|
|
41
|
-
def eval_monad_enumerate(a):
|
|
38
|
+
def eval_monad_enumerate(a, backend):
|
|
42
39
|
"""
|
|
43
40
|
|
|
44
41
|
!a [Enumerate]
|
|
@@ -50,9 +47,9 @@ def eval_monad_enumerate(a):
|
|
|
50
47
|
!10 --> [0 1 2 3 4 5 6 7 8 9]
|
|
51
48
|
|
|
52
49
|
"""
|
|
53
|
-
if not is_integer(a):
|
|
50
|
+
if not backend.is_integer(a):
|
|
54
51
|
raise RuntimeError(f"enumerate: invalid type error: {a}")
|
|
55
|
-
return
|
|
52
|
+
return bknp.arange(int(a))
|
|
56
53
|
|
|
57
54
|
|
|
58
55
|
def eval_monad_expand_where(a):
|
|
@@ -79,7 +76,7 @@ def eval_monad_expand_where(a):
|
|
|
79
76
|
|
|
80
77
|
"""
|
|
81
78
|
arr = a if is_list(a) else [a]
|
|
82
|
-
return
|
|
79
|
+
return bknp.repeat(bknp.arange(len(arr)), arr)
|
|
83
80
|
|
|
84
81
|
|
|
85
82
|
def eval_monad_first(a):
|
|
@@ -101,7 +98,7 @@ def eval_monad_first(a):
|
|
|
101
98
|
return a if is_empty(a) or not is_iterable(a) else a[0]
|
|
102
99
|
|
|
103
100
|
|
|
104
|
-
def eval_monad_floor(a):
|
|
101
|
+
def eval_monad_floor(a, backend):
|
|
105
102
|
"""
|
|
106
103
|
|
|
107
104
|
_a [Floor]
|
|
@@ -119,18 +116,10 @@ def eval_monad_floor(a):
|
|
|
119
116
|
_1e100 --> 1.0e+100 :"if precision < 100 digits"
|
|
120
117
|
|
|
121
118
|
"""
|
|
122
|
-
|
|
123
|
-
result = np.floor(np.asarray(x, dtype=float))
|
|
124
|
-
# Handle both numpy arrays and torch tensors
|
|
125
|
-
if hasattr(result, 'astype'):
|
|
126
|
-
return result.astype(int)
|
|
127
|
-
elif hasattr(result, 'to'): # torch tensor - .to(int) works
|
|
128
|
-
return result.to(int)
|
|
129
|
-
return int(result)
|
|
130
|
-
return vec_fn(a, _floor_to_int)
|
|
119
|
+
return backend.vec_fn(a, backend.floor_to_int)
|
|
131
120
|
|
|
132
121
|
|
|
133
|
-
def eval_monad_format(a):
|
|
122
|
+
def eval_monad_format(a, backend):
|
|
134
123
|
"""
|
|
135
124
|
|
|
136
125
|
$a [Format]
|
|
@@ -148,10 +137,10 @@ def eval_monad_format(a):
|
|
|
148
137
|
$:foo --> ":foo"
|
|
149
138
|
|
|
150
139
|
"""
|
|
151
|
-
return f":{a}" if isinstance(a, KGSym) else vec_fn(a, eval_monad_format) if is_list(a) else str(a)
|
|
140
|
+
return f":{a}" if isinstance(a, KGSym) else backend.vec_fn(a, lambda x: eval_monad_format(x, backend)) if is_list(a) else str(a)
|
|
152
141
|
|
|
153
142
|
|
|
154
|
-
def eval_monad_grade_up(a):
|
|
143
|
+
def eval_monad_grade_up(a, backend):
|
|
155
144
|
"""
|
|
156
145
|
|
|
157
146
|
<a [Grade-Up]
|
|
@@ -176,10 +165,10 @@ def eval_monad_grade_up(a):
|
|
|
176
165
|
>[[1] [2] [3]] --> [2 1 0]
|
|
177
166
|
|
|
178
167
|
"""
|
|
179
|
-
return kg_argsort(kg_asarray(a))
|
|
168
|
+
return kg_argsort(backend.kg_asarray(a), backend)
|
|
180
169
|
|
|
181
170
|
|
|
182
|
-
def eval_monad_grade_down(a):
|
|
171
|
+
def eval_monad_grade_down(a, backend):
|
|
183
172
|
"""
|
|
184
173
|
|
|
185
174
|
>a [Grade-Down]
|
|
@@ -187,10 +176,10 @@ def eval_monad_grade_down(a):
|
|
|
187
176
|
See [Grade-Up].
|
|
188
177
|
|
|
189
178
|
"""
|
|
190
|
-
return kg_argsort(kg_asarray(a), descending=True)
|
|
179
|
+
return kg_argsort(backend.kg_asarray(a), backend, descending=True)
|
|
191
180
|
|
|
192
181
|
|
|
193
|
-
def eval_monad_groupby(a):
|
|
182
|
+
def eval_monad_groupby(a, backend):
|
|
194
183
|
"""
|
|
195
184
|
|
|
196
185
|
=a [Group]
|
|
@@ -207,15 +196,15 @@ def eval_monad_groupby(a):
|
|
|
207
196
|
="hello foo" --> [[0] [1] [2 3] [4 7 8] [5] [6]]
|
|
208
197
|
|
|
209
198
|
"""
|
|
210
|
-
arr = kg_asarray(a)
|
|
211
|
-
if array_size(arr) == 0:
|
|
199
|
+
arr = backend.kg_asarray(a)
|
|
200
|
+
if backend.array_size(arr) == 0:
|
|
212
201
|
return arr
|
|
213
|
-
vals, inverse =
|
|
214
|
-
groups = [
|
|
215
|
-
return kg_asarray(groups)
|
|
202
|
+
vals, inverse = bknp.unique(arr, return_inverse=True)
|
|
203
|
+
groups = [bknp.where(inverse == i)[0] for i in range(len(vals))]
|
|
204
|
+
return backend.kg_asarray(groups)
|
|
216
205
|
|
|
217
206
|
|
|
218
|
-
def eval_monad_list(a):
|
|
207
|
+
def eval_monad_list(a, backend):
|
|
219
208
|
"""
|
|
220
209
|
|
|
221
210
|
,a [List]
|
|
@@ -229,12 +218,10 @@ def eval_monad_list(a):
|
|
|
229
218
|
"""
|
|
230
219
|
if is_char(a):
|
|
231
220
|
return str(a)
|
|
232
|
-
|
|
233
|
-
return np.asarray([a],dtype=object) # np interprets ':foo" as ':fo"
|
|
234
|
-
return np.asarray([a])
|
|
221
|
+
return backend.kg_asarray([a])
|
|
235
222
|
|
|
236
223
|
|
|
237
|
-
def eval_monad_negate(a):
|
|
224
|
+
def eval_monad_negate(a, backend):
|
|
238
225
|
"""
|
|
239
226
|
|
|
240
227
|
-a [Negate]
|
|
@@ -247,10 +234,10 @@ def eval_monad_negate(a):
|
|
|
247
234
|
-1.23 --> -1.23
|
|
248
235
|
|
|
249
236
|
"""
|
|
250
|
-
return vec_fn(a, lambda x: np.negative(kg_asarray(x)))
|
|
237
|
+
return backend.vec_fn(a, lambda x: backend.np.negative(backend.kg_asarray(x)))
|
|
251
238
|
|
|
252
239
|
|
|
253
|
-
def eval_monad_not(a):
|
|
240
|
+
def eval_monad_not(a, backend):
|
|
254
241
|
"""
|
|
255
242
|
|
|
256
243
|
~a [Not]
|
|
@@ -266,11 +253,11 @@ def eval_monad_not(a):
|
|
|
266
253
|
|
|
267
254
|
"""
|
|
268
255
|
def _neg(x):
|
|
269
|
-
return 1 if is_empty(x) else 0 if is_dict(x) or isinstance(x, (KGFn, KGSym)) else kg_truth(
|
|
270
|
-
return vec_fn(a, _neg) if not is_empty(a) else _neg(a)
|
|
256
|
+
return 1 if is_empty(x) else 0 if is_dict(x) or isinstance(x, (KGFn, KGSym)) else kg_truth(bknp.logical_not(bknp.asarray(x, dtype=object)))
|
|
257
|
+
return backend.vec_fn(a, _neg) if not is_empty(a) else _neg(a)
|
|
271
258
|
|
|
272
259
|
|
|
273
|
-
def eval_monad_range(a):
|
|
260
|
+
def eval_monad_range(a, backend):
|
|
274
261
|
"""
|
|
275
262
|
|
|
276
263
|
?a [Range]
|
|
@@ -283,28 +270,19 @@ def eval_monad_range(a):
|
|
|
283
270
|
?"aaabbcccd" --> "abcd"
|
|
284
271
|
|
|
285
272
|
"""
|
|
273
|
+
np_backend = backend.np
|
|
286
274
|
if isinstance(a, str):
|
|
287
|
-
return ''.join(
|
|
288
|
-
elif
|
|
289
|
-
|
|
290
|
-
|
|
275
|
+
return ''.join(bknp.unique(backend.str_to_chr_arr(a)))
|
|
276
|
+
elif np_backend.isarray(a):
|
|
277
|
+
dtype_kind = backend.get_dtype_kind(a)
|
|
278
|
+
if dtype_kind != 'O' and a.ndim > 1:
|
|
279
|
+
# Use numpy for unique with return_index across backends
|
|
280
|
+
a_np = backend.to_numpy(a) if backend.is_backend_array(a) else a
|
|
281
|
+
_, ids = bknp.unique(a_np, axis=0, return_index=True)
|
|
282
|
+
ids.sort()
|
|
283
|
+
return a[ids]
|
|
291
284
|
else:
|
|
292
285
|
# handle the jagged / mixed array case
|
|
293
|
-
# from functools import total_ordering
|
|
294
|
-
# @total_ordering
|
|
295
|
-
# class Wrapper:
|
|
296
|
-
# def __init__(self, x):
|
|
297
|
-
# self.x = x
|
|
298
|
-
# def __eq__(self,o):
|
|
299
|
-
# print("eq")
|
|
300
|
-
# return array_equal(self.x, o.x)
|
|
301
|
-
# def __ne__(self,o):
|
|
302
|
-
# return not array_equal(self.x, o.x)
|
|
303
|
-
# def __lt__(self, o):
|
|
304
|
-
# u = np.sort(np.asarray([self.x, o.x]))
|
|
305
|
-
# return u[0] == self.x
|
|
306
|
-
# # return u[0] if isinstance(u,np.ndarray) else u
|
|
307
|
-
# _,ids = np.unique([Wrapper(x) for x in a], return_index=True)
|
|
308
286
|
# TODO: Make UNIQUE work. this feels so dirty.
|
|
309
287
|
s = set()
|
|
310
288
|
arr = []
|
|
@@ -313,13 +291,11 @@ def eval_monad_range(a):
|
|
|
313
291
|
if sx not in s:
|
|
314
292
|
s.add(sx)
|
|
315
293
|
arr.append(x)
|
|
316
|
-
return
|
|
317
|
-
ids.sort()
|
|
318
|
-
a = a[ids]
|
|
294
|
+
return backend.kg_asarray(arr)
|
|
319
295
|
return a
|
|
320
296
|
|
|
321
297
|
|
|
322
|
-
def eval_monad_reciprocal(a):
|
|
298
|
+
def eval_monad_reciprocal(a, backend):
|
|
323
299
|
"""
|
|
324
300
|
|
|
325
301
|
%a [Reciprocal]
|
|
@@ -333,7 +309,11 @@ def eval_monad_reciprocal(a):
|
|
|
333
309
|
%0.1 --> 10.0
|
|
334
310
|
|
|
335
311
|
"""
|
|
336
|
-
|
|
312
|
+
if not is_list(a) and backend.is_number(a):
|
|
313
|
+
a_val = backend.scalar_to_python(a) if backend.is_backend_array(a) else a
|
|
314
|
+
if a_val == 0:
|
|
315
|
+
return KLONG_UNDEFINED
|
|
316
|
+
return backend.vec_fn(a, lambda x: bknp.reciprocal(bknp.asarray(x, dtype=float)))
|
|
337
317
|
|
|
338
318
|
|
|
339
319
|
def eval_monad_reverse(a):
|
|
@@ -353,7 +333,7 @@ def eval_monad_reverse(a):
|
|
|
353
333
|
return a[::-1]
|
|
354
334
|
|
|
355
335
|
|
|
356
|
-
def eval_monad_shape(a):
|
|
336
|
+
def eval_monad_shape(a, backend):
|
|
357
337
|
"""
|
|
358
338
|
|
|
359
339
|
^a [Shape]
|
|
@@ -405,12 +385,20 @@ def eval_monad_shape(a):
|
|
|
405
385
|
|
|
406
386
|
"""
|
|
407
387
|
|
|
388
|
+
def _normalize_backend_array(x):
|
|
389
|
+
return backend.to_numpy(x) if backend.is_backend_array(x) else x
|
|
390
|
+
|
|
408
391
|
def _a(x): # use numpy's natural shape by replacing all strings with arrays
|
|
409
|
-
|
|
410
|
-
|
|
392
|
+
x = _normalize_backend_array(x)
|
|
393
|
+
return bknp.asarray([
|
|
394
|
+
bknp.empty(len(y)) if isinstance(y, str) else (_a(y) if is_list(y) else _normalize_backend_array(y))
|
|
395
|
+
for y in x
|
|
396
|
+
])
|
|
397
|
+
a = _normalize_backend_array(a)
|
|
398
|
+
return 0 if is_atom(a) else bknp.asarray([len(a)]) if isinstance(a, str) else bknp.asarray(_a(a).shape)
|
|
411
399
|
|
|
412
400
|
|
|
413
|
-
def eval_monad_size(a):
|
|
401
|
+
def eval_monad_size(a, backend):
|
|
414
402
|
"""
|
|
415
403
|
|
|
416
404
|
#a [Size]
|
|
@@ -429,7 +417,7 @@ def eval_monad_size(a):
|
|
|
429
417
|
#0cA --> 65
|
|
430
418
|
|
|
431
419
|
"""
|
|
432
|
-
return np.abs(a) if is_number(a) else ord(a) if is_char(a) else len(a)
|
|
420
|
+
return backend.np.abs(a) if backend.is_number(a) else ord(a) if is_char(a) else len(a)
|
|
433
421
|
|
|
434
422
|
|
|
435
423
|
def eval_monad_transpose(a):
|
|
@@ -444,10 +432,10 @@ def eval_monad_transpose(a):
|
|
|
444
432
|
+[] --> []
|
|
445
433
|
|
|
446
434
|
"""
|
|
447
|
-
return
|
|
435
|
+
return bknp.transpose(bknp.asarray(a))
|
|
448
436
|
|
|
449
437
|
|
|
450
|
-
def eval_monad_undefined(a):
|
|
438
|
+
def eval_monad_undefined(a, backend):
|
|
451
439
|
"""
|
|
452
440
|
|
|
453
441
|
:_a [Undefined]
|
|
@@ -462,7 +450,7 @@ def eval_monad_undefined(a):
|
|
|
462
450
|
:_:valid --> 0
|
|
463
451
|
|
|
464
452
|
"""
|
|
465
|
-
return kg_truth(a is None or
|
|
453
|
+
return kg_truth(a is None or a is KLONG_UNDEFINED)
|
|
466
454
|
|
|
467
455
|
|
|
468
456
|
def eval_monad_track(a):
|
|
@@ -488,18 +476,40 @@ def eval_monad_grad(klong, a):
|
|
|
488
476
|
|
|
489
477
|
|
|
490
478
|
def create_monad_functions(klong):
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
479
|
+
backend = klong._backend
|
|
480
|
+
|
|
481
|
+
# Simple monads that don't need backend or klong
|
|
482
|
+
simple = {
|
|
483
|
+
'@': eval_monad_atom,
|
|
484
|
+
'&': eval_monad_expand_where,
|
|
485
|
+
'*': eval_monad_first,
|
|
486
|
+
'|': eval_monad_reverse,
|
|
487
|
+
'+': eval_monad_transpose,
|
|
488
|
+
'˙': eval_monad_track,
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
# Monads needing backend
|
|
492
|
+
backend_monads = {
|
|
493
|
+
',': lambda a: eval_monad_list(a, backend),
|
|
494
|
+
':#': lambda a: eval_monad_char(a, backend),
|
|
495
|
+
'!': lambda a: eval_monad_enumerate(a, backend),
|
|
496
|
+
'_': lambda a: eval_monad_floor(a, backend),
|
|
497
|
+
'$': lambda a: eval_monad_format(a, backend),
|
|
498
|
+
'<': lambda a: eval_monad_grade_up(a, backend),
|
|
499
|
+
'>': lambda a: eval_monad_grade_down(a, backend),
|
|
500
|
+
'=': lambda a: eval_monad_groupby(a, backend),
|
|
501
|
+
'-': lambda a: eval_monad_negate(a, backend),
|
|
502
|
+
'~': lambda a: eval_monad_not(a, backend),
|
|
503
|
+
'?': lambda a: eval_monad_range(a, backend),
|
|
504
|
+
'%': lambda a: eval_monad_reciprocal(a, backend),
|
|
505
|
+
'#': lambda a: eval_monad_size(a, backend),
|
|
506
|
+
':_': lambda a: eval_monad_undefined(a, backend),
|
|
507
|
+
'^': lambda a: eval_monad_shape(a, backend),
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
# Monads needing klong
|
|
511
|
+
klong_monads = {
|
|
512
|
+
'∇': lambda a: eval_monad_grad(klong, a),
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
return {**simple, **backend_monads, **klong_monads}
|