@aleph-ai/tinyaleph 1.0.2 → 1.1.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/core/lambda.js ADDED
@@ -0,0 +1,845 @@
1
+ /**
2
+ * λ-Calculus Translation Layer for Prime-Indexed Semantic Calculi
3
+ *
4
+ * Provides a denotational semantics via λ-calculus:
5
+ * - τ (tau) translation function from typed terms to λ-expressions
6
+ * - Compositional semantics via function application
7
+ * - Type preservation during translation
8
+ * - Denotational semantics bridge
9
+ *
10
+ * The translation τ maps:
11
+ * - N(p) → λx.p (constant function returning prime p)
12
+ * - A(p) → λf.λx.f(p,x) (operator awaiting application)
13
+ * - FUSE(p,q,r) → λx.(p+q+r) (fusion to sum)
14
+ * - A(p)N(q) → (τ(A(p)))(τ(N(q))) = p ⊕ q
15
+ * - S₁ ◦ S₂ → (τ(S₁), τ(S₂))
16
+ * - S₁ ⇒ S₂ → τ(S₁) → τ(S₂)
17
+ */
18
+
19
+ const {
20
+ NounTerm,
21
+ AdjTerm,
22
+ ChainTerm,
23
+ FusionTerm,
24
+ NounSentence,
25
+ SeqSentence,
26
+ ImplSentence,
27
+ N, A, FUSE, CHAIN
28
+ } = require('./types');
29
+
30
+ const {
31
+ ReductionSystem,
32
+ DEFAULT_OPERATOR
33
+ } = require('./reduction');
34
+
35
+ // ============================================================================
36
+ // λ-EXPRESSION AST
37
+ // ============================================================================
38
+
39
+ /**
40
+ * Base class for λ-expressions
41
+ */
42
+ class LambdaExpr {
43
+ /**
44
+ * Get the type of this expression
45
+ */
46
+ getType() {
47
+ throw new Error('Must be implemented by subclass');
48
+ }
49
+
50
+ /**
51
+ * Convert to string representation
52
+ */
53
+ toString() {
54
+ throw new Error('Must be implemented by subclass');
55
+ }
56
+
57
+ /**
58
+ * Check if this is a value (fully evaluated)
59
+ */
60
+ isValue() {
61
+ return false;
62
+ }
63
+
64
+ /**
65
+ * Substitute variable x with expression e
66
+ */
67
+ substitute(x, e) {
68
+ throw new Error('Must be implemented by subclass');
69
+ }
70
+
71
+ /**
72
+ * Get free variables
73
+ */
74
+ freeVars() {
75
+ return new Set();
76
+ }
77
+
78
+ /**
79
+ * Alpha-equivalence check
80
+ */
81
+ alphaEquals(other) {
82
+ return this.toString() === other.toString();
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Variable expression
88
+ */
89
+ class VarExpr extends LambdaExpr {
90
+ constructor(name, type = null) {
91
+ super();
92
+ this.name = name;
93
+ this.type = type;
94
+ }
95
+
96
+ getType() {
97
+ return this.type;
98
+ }
99
+
100
+ toString() {
101
+ return this.name;
102
+ }
103
+
104
+ substitute(x, e) {
105
+ if (this.name === x) return e;
106
+ return this;
107
+ }
108
+
109
+ freeVars() {
110
+ return new Set([this.name]);
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Constant (prime number) expression
116
+ */
117
+ class ConstExpr extends LambdaExpr {
118
+ constructor(value) {
119
+ super();
120
+ this.value = value;
121
+ }
122
+
123
+ getType() {
124
+ return { kind: 'const', value: this.value };
125
+ }
126
+
127
+ toString() {
128
+ return String(this.value);
129
+ }
130
+
131
+ isValue() {
132
+ return true;
133
+ }
134
+
135
+ substitute(x, e) {
136
+ return this;
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Lambda abstraction: λx.body
142
+ */
143
+ class LamExpr extends LambdaExpr {
144
+ constructor(param, body, paramType = null) {
145
+ super();
146
+ this.param = param;
147
+ this.body = body;
148
+ this.paramType = paramType;
149
+ }
150
+
151
+ getType() {
152
+ return {
153
+ kind: 'function',
154
+ paramType: this.paramType,
155
+ returnType: this.body.getType()
156
+ };
157
+ }
158
+
159
+ toString() {
160
+ const typeAnnotation = this.paramType ? `:${JSON.stringify(this.paramType)}` : '';
161
+ return `(λ${this.param}${typeAnnotation}.${this.body})`;
162
+ }
163
+
164
+ isValue() {
165
+ return true; // Lambdas are values
166
+ }
167
+
168
+ substitute(x, e) {
169
+ if (this.param === x) {
170
+ // x is bound here, no substitution in body
171
+ return this;
172
+ }
173
+
174
+ // Check for variable capture
175
+ const freeInE = e.freeVars();
176
+ if (freeInE.has(this.param)) {
177
+ // Alpha-rename to avoid capture
178
+ const fresh = this.freshVar(this.param);
179
+ const renamedBody = this.body.substitute(this.param, new VarExpr(fresh));
180
+ return new LamExpr(fresh, renamedBody.substitute(x, e), this.paramType);
181
+ }
182
+
183
+ return new LamExpr(this.param, this.body.substitute(x, e), this.paramType);
184
+ }
185
+
186
+ freeVars() {
187
+ const vars = this.body.freeVars();
188
+ vars.delete(this.param);
189
+ return vars;
190
+ }
191
+
192
+ freshVar(base) {
193
+ return `${base}'`;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Application expression: e1 e2
199
+ */
200
+ class AppExpr extends LambdaExpr {
201
+ constructor(func, arg) {
202
+ super();
203
+ this.func = func;
204
+ this.arg = arg;
205
+ }
206
+
207
+ getType() {
208
+ const funcType = this.func.getType();
209
+ if (funcType && funcType.kind === 'function') {
210
+ return funcType.returnType;
211
+ }
212
+ return null;
213
+ }
214
+
215
+ toString() {
216
+ return `(${this.func} ${this.arg})`;
217
+ }
218
+
219
+ substitute(x, e) {
220
+ return new AppExpr(
221
+ this.func.substitute(x, e),
222
+ this.arg.substitute(x, e)
223
+ );
224
+ }
225
+
226
+ freeVars() {
227
+ const vars = this.func.freeVars();
228
+ for (const v of this.arg.freeVars()) {
229
+ vars.add(v);
230
+ }
231
+ return vars;
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Pair expression: (e1, e2) for sentence composition
237
+ */
238
+ class PairExpr extends LambdaExpr {
239
+ constructor(left, right) {
240
+ super();
241
+ this.left = left;
242
+ this.right = right;
243
+ }
244
+
245
+ getType() {
246
+ return {
247
+ kind: 'pair',
248
+ leftType: this.left.getType(),
249
+ rightType: this.right.getType()
250
+ };
251
+ }
252
+
253
+ toString() {
254
+ return `⟨${this.left}, ${this.right}⟩`;
255
+ }
256
+
257
+ isValue() {
258
+ return this.left.isValue() && this.right.isValue();
259
+ }
260
+
261
+ substitute(x, e) {
262
+ return new PairExpr(
263
+ this.left.substitute(x, e),
264
+ this.right.substitute(x, e)
265
+ );
266
+ }
267
+
268
+ freeVars() {
269
+ const vars = this.left.freeVars();
270
+ for (const v of this.right.freeVars()) {
271
+ vars.add(v);
272
+ }
273
+ return vars;
274
+ }
275
+ }
276
+
277
+ /**
278
+ * Implication expression: e1 → e2
279
+ */
280
+ class ImplExpr extends LambdaExpr {
281
+ constructor(antecedent, consequent) {
282
+ super();
283
+ this.antecedent = antecedent;
284
+ this.consequent = consequent;
285
+ }
286
+
287
+ getType() {
288
+ return {
289
+ kind: 'implication',
290
+ anteType: this.antecedent.getType(),
291
+ consType: this.consequent.getType()
292
+ };
293
+ }
294
+
295
+ toString() {
296
+ return `(${this.antecedent} → ${this.consequent})`;
297
+ }
298
+
299
+ isValue() {
300
+ return this.antecedent.isValue() && this.consequent.isValue();
301
+ }
302
+
303
+ substitute(x, e) {
304
+ return new ImplExpr(
305
+ this.antecedent.substitute(x, e),
306
+ this.consequent.substitute(x, e)
307
+ );
308
+ }
309
+
310
+ freeVars() {
311
+ const vars = this.antecedent.freeVars();
312
+ for (const v of this.consequent.freeVars()) {
313
+ vars.add(v);
314
+ }
315
+ return vars;
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Primitive operator application: ⊕(p, q)
321
+ */
322
+ class PrimOpExpr extends LambdaExpr {
323
+ constructor(op, left, right) {
324
+ super();
325
+ this.op = op; // String name of operator
326
+ this.left = left;
327
+ this.right = right;
328
+ }
329
+
330
+ getType() {
331
+ return { kind: 'prime' };
332
+ }
333
+
334
+ toString() {
335
+ return `(${this.left} ⊕ ${this.right})`;
336
+ }
337
+
338
+ substitute(x, e) {
339
+ return new PrimOpExpr(
340
+ this.op,
341
+ this.left.substitute(x, e),
342
+ this.right.substitute(x, e)
343
+ );
344
+ }
345
+
346
+ freeVars() {
347
+ const vars = this.left.freeVars();
348
+ for (const v of this.right.freeVars()) {
349
+ vars.add(v);
350
+ }
351
+ return vars;
352
+ }
353
+ }
354
+
355
+ // ============================================================================
356
+ // τ TRANSLATION FUNCTION
357
+ // ============================================================================
358
+
359
+ /**
360
+ * Translator - Implements the τ function from Section 4
361
+ */
362
+ class Translator {
363
+ constructor(operator = DEFAULT_OPERATOR) {
364
+ this.operator = operator;
365
+ this.varCounter = 0;
366
+ }
367
+
368
+ /**
369
+ * Generate a fresh variable name
370
+ */
371
+ freshVar() {
372
+ return `x${this.varCounter++}`;
373
+ }
374
+
375
+ /**
376
+ * τ: Term → LambdaExpr
377
+ * Main translation function
378
+ */
379
+ translate(term) {
380
+ // τ(N(p)) = p (constant)
381
+ if (term instanceof NounTerm) {
382
+ return new ConstExpr(term.prime);
383
+ }
384
+
385
+ // τ(A(p)) = λf.λx.⊕(p, f(x))
386
+ // Simplified: λx.⊕(p, x)
387
+ if (term instanceof AdjTerm) {
388
+ const x = this.freshVar();
389
+ return new LamExpr(
390
+ x,
391
+ new PrimOpExpr('⊕', new ConstExpr(term.prime), new VarExpr(x)),
392
+ { kind: 'prime' }
393
+ );
394
+ }
395
+
396
+ // τ(FUSE(p,q,r)) = p+q+r (constant)
397
+ if (term instanceof FusionTerm) {
398
+ return new ConstExpr(term.getFusedPrime());
399
+ }
400
+
401
+ // τ(A(p₁)...A(pₖ)N(q)) = ((τ(A(p₁)) ... (τ(A(pₖ)) τ(N(q))))
402
+ if (term instanceof ChainTerm) {
403
+ // Start with the noun
404
+ let result = this.translate(term.noun);
405
+
406
+ // Apply operators from innermost (rightmost) to outermost (leftmost)
407
+ for (let i = term.operators.length - 1; i >= 0; i--) {
408
+ const op = term.operators[i];
409
+ const opLambda = this.translate(op);
410
+ result = new AppExpr(opLambda, result);
411
+ }
412
+
413
+ return result;
414
+ }
415
+
416
+ // τ(NounSentence(e)) = τ(e)
417
+ if (term instanceof NounSentence) {
418
+ return this.translate(term.expr);
419
+ }
420
+
421
+ // τ(S₁ ◦ S₂) = ⟨τ(S₁), τ(S₂)⟩
422
+ if (term instanceof SeqSentence) {
423
+ return new PairExpr(
424
+ this.translate(term.left),
425
+ this.translate(term.right)
426
+ );
427
+ }
428
+
429
+ // τ(S₁ ⇒ S₂) = τ(S₁) → τ(S₂)
430
+ if (term instanceof ImplSentence) {
431
+ return new ImplExpr(
432
+ this.translate(term.antecedent),
433
+ this.translate(term.consequent)
434
+ );
435
+ }
436
+
437
+ throw new Error(`Cannot translate: ${term}`);
438
+ }
439
+
440
+ /**
441
+ * Translate and show the translation steps
442
+ */
443
+ translateWithTrace(term) {
444
+ const result = this.translate(term);
445
+ return {
446
+ source: term.signature(),
447
+ target: result.toString(),
448
+ type: result.getType()
449
+ };
450
+ }
451
+ }
452
+
453
+ // ============================================================================
454
+ // λ-CALCULUS EVALUATOR
455
+ // ============================================================================
456
+
457
+ /**
458
+ * Call-by-value evaluator for λ-expressions
459
+ */
460
+ class LambdaEvaluator {
461
+ constructor(operator = DEFAULT_OPERATOR) {
462
+ this.operator = operator;
463
+ this.maxSteps = 1000;
464
+ }
465
+
466
+ /**
467
+ * Evaluate one step (small-step semantics)
468
+ */
469
+ step(expr) {
470
+ // Application of lambda to value: (λx.e) v → e[x := v]
471
+ if (expr instanceof AppExpr) {
472
+ // First evaluate function to value
473
+ if (!expr.func.isValue()) {
474
+ const newFunc = this.step(expr.func);
475
+ if (newFunc) {
476
+ return new AppExpr(newFunc, expr.arg);
477
+ }
478
+ }
479
+
480
+ // Then evaluate argument to value
481
+ if (!expr.arg.isValue()) {
482
+ const newArg = this.step(expr.arg);
483
+ if (newArg) {
484
+ return new AppExpr(expr.func, newArg);
485
+ }
486
+ }
487
+
488
+ // Both are values, perform β-reduction
489
+ if (expr.func instanceof LamExpr && expr.arg.isValue()) {
490
+ return expr.func.body.substitute(expr.func.param, expr.arg);
491
+ }
492
+ }
493
+
494
+ // Primitive operator application
495
+ if (expr instanceof PrimOpExpr) {
496
+ // Evaluate operands first
497
+ if (!expr.left.isValue()) {
498
+ const newLeft = this.step(expr.left);
499
+ if (newLeft) {
500
+ return new PrimOpExpr(expr.op, newLeft, expr.right);
501
+ }
502
+ }
503
+
504
+ if (!expr.right.isValue()) {
505
+ const newRight = this.step(expr.right);
506
+ if (newRight) {
507
+ return new PrimOpExpr(expr.op, expr.left, newRight);
508
+ }
509
+ }
510
+
511
+ // Both values, apply operator
512
+ if (expr.left instanceof ConstExpr && expr.right instanceof ConstExpr) {
513
+ const p = expr.left.value;
514
+ const q = expr.right.value;
515
+ if (this.operator.canApply(p, q)) {
516
+ const result = this.operator.apply(p, q);
517
+ return new ConstExpr(result);
518
+ } else if (this.operator.canApply(q, p)) {
519
+ const result = this.operator.apply(q, p);
520
+ return new ConstExpr(result);
521
+ }
522
+ // If neither ordering works, just return the larger value
523
+ return new ConstExpr(Math.max(p, q));
524
+ }
525
+ }
526
+
527
+ // Pair reduction
528
+ if (expr instanceof PairExpr) {
529
+ if (!expr.left.isValue()) {
530
+ const newLeft = this.step(expr.left);
531
+ if (newLeft) {
532
+ return new PairExpr(newLeft, expr.right);
533
+ }
534
+ }
535
+
536
+ if (!expr.right.isValue()) {
537
+ const newRight = this.step(expr.right);
538
+ if (newRight) {
539
+ return new PairExpr(expr.left, newRight);
540
+ }
541
+ }
542
+ }
543
+
544
+ // Implication reduction
545
+ if (expr instanceof ImplExpr) {
546
+ if (!expr.antecedent.isValue()) {
547
+ const newAnte = this.step(expr.antecedent);
548
+ if (newAnte) {
549
+ return new ImplExpr(newAnte, expr.consequent);
550
+ }
551
+ }
552
+
553
+ if (!expr.consequent.isValue()) {
554
+ const newCons = this.step(expr.consequent);
555
+ if (newCons) {
556
+ return new ImplExpr(expr.antecedent, newCons);
557
+ }
558
+ }
559
+ }
560
+
561
+ return null;
562
+ }
563
+
564
+ /**
565
+ * Fully evaluate expression to value
566
+ */
567
+ evaluate(expr) {
568
+ let current = expr;
569
+ let steps = 0;
570
+
571
+ while (steps < this.maxSteps) {
572
+ const next = this.step(current);
573
+ if (!next) break;
574
+ current = next;
575
+ steps++;
576
+ }
577
+
578
+ return {
579
+ result: current,
580
+ steps,
581
+ isValue: current.isValue()
582
+ };
583
+ }
584
+ }
585
+
586
+ // ============================================================================
587
+ // COMPOSITIONAL SEMANTICS
588
+ // ============================================================================
589
+
590
+ /**
591
+ * Denotational semantics via λ-calculus interpretation
592
+ */
593
+ class Semantics {
594
+ constructor(operator = DEFAULT_OPERATOR) {
595
+ this.translator = new Translator(operator);
596
+ this.evaluator = new LambdaEvaluator(operator);
597
+ this.reducer = new ReductionSystem(operator);
598
+ }
599
+
600
+ /**
601
+ * Get the denotation of a term
602
+ * [[e]] = evaluate(τ(e))
603
+ */
604
+ denote(term) {
605
+ const lambda = this.translator.translate(term);
606
+ const result = this.evaluator.evaluate(lambda);
607
+ return result.result;
608
+ }
609
+
610
+ /**
611
+ * Check semantic equivalence
612
+ * [[e₁]] = [[e₂]]
613
+ */
614
+ equivalent(term1, term2) {
615
+ const d1 = this.denote(term1);
616
+ const d2 = this.denote(term2);
617
+
618
+ if (d1 instanceof ConstExpr && d2 instanceof ConstExpr) {
619
+ return d1.value === d2.value;
620
+ }
621
+
622
+ return d1.toString() === d2.toString();
623
+ }
624
+
625
+ /**
626
+ * Verify operational and denotational semantics agree
627
+ * Theorem: If e →* v in operational semantics, then [[e]] = v
628
+ */
629
+ verifySemanticEquivalence(term) {
630
+ // Get operational result
631
+ const opResult = this.reducer.evaluate(term);
632
+
633
+ // Get denotational result
634
+ const denResult = this.denote(term);
635
+
636
+ // Compare
637
+ let equivalent = false;
638
+ if (opResult instanceof NounTerm && denResult instanceof ConstExpr) {
639
+ equivalent = opResult.prime === denResult.value;
640
+ }
641
+
642
+ return {
643
+ term: term.signature(),
644
+ operational: opResult instanceof NounTerm ? opResult.prime : opResult.signature(),
645
+ denotational: denResult instanceof ConstExpr ? denResult.value : denResult.toString(),
646
+ equivalent
647
+ };
648
+ }
649
+ }
650
+
651
+ // ============================================================================
652
+ // INTERPRETATION (Section 5 - Prime → Concept mapping)
653
+ // ============================================================================
654
+
655
+ /**
656
+ * ConceptInterpreter - Maps primes to semantic concepts
657
+ */
658
+ class ConceptInterpreter {
659
+ constructor() {
660
+ // Default concept mappings (can be customized)
661
+ this.nounConcepts = new Map([
662
+ [2, 'existence'],
663
+ [3, 'unity'],
664
+ [5, 'life'],
665
+ [7, 'truth'],
666
+ [11, 'consciousness'],
667
+ [13, 'knowledge'],
668
+ [17, 'wisdom'],
669
+ [19, 'love'],
670
+ [23, 'creation'],
671
+ [29, 'infinity']
672
+ ]);
673
+
674
+ this.adjConcepts = new Map([
675
+ [2, 'dual'],
676
+ [3, 'triple'],
677
+ [5, 'vital'],
678
+ [7, 'true'],
679
+ [11, 'conscious'],
680
+ [13, 'knowing'],
681
+ [17, 'wise'],
682
+ [19, 'loving'],
683
+ [23, 'creative'],
684
+ [29, 'infinite']
685
+ ]);
686
+ }
687
+
688
+ /**
689
+ * Interpret a noun term as concept
690
+ */
691
+ interpretNoun(term) {
692
+ if (!(term instanceof NounTerm)) {
693
+ throw new Error('Expected NounTerm');
694
+ }
695
+
696
+ const p = term.prime;
697
+ if (this.nounConcepts.has(p)) {
698
+ return this.nounConcepts.get(p);
699
+ }
700
+
701
+ // Generate description for unknown primes
702
+ return `concept_${p}`;
703
+ }
704
+
705
+ /**
706
+ * Interpret an adjective term as modifier
707
+ */
708
+ interpretAdj(term) {
709
+ if (!(term instanceof AdjTerm)) {
710
+ throw new Error('Expected AdjTerm');
711
+ }
712
+
713
+ const p = term.prime;
714
+ if (this.adjConcepts.has(p)) {
715
+ return this.adjConcepts.get(p);
716
+ }
717
+
718
+ return `modifier_${p}`;
719
+ }
720
+
721
+ /**
722
+ * Interpret a chain as modified concept
723
+ */
724
+ interpretChain(term) {
725
+ if (!(term instanceof ChainTerm)) {
726
+ throw new Error('Expected ChainTerm');
727
+ }
728
+
729
+ const noun = this.interpretNoun(term.noun);
730
+ const adjs = term.operators.map(op => this.interpretAdj(op));
731
+
732
+ // Build phrase: adj1 adj2 ... noun
733
+ return [...adjs, noun].join(' ');
734
+ }
735
+
736
+ /**
737
+ * Full interpretation of any term
738
+ */
739
+ interpret(term) {
740
+ if (term instanceof NounTerm) {
741
+ return this.interpretNoun(term);
742
+ }
743
+ if (term instanceof AdjTerm) {
744
+ return this.interpretAdj(term);
745
+ }
746
+ if (term instanceof ChainTerm) {
747
+ return this.interpretChain(term);
748
+ }
749
+ if (term instanceof FusionTerm) {
750
+ return `fusion(${term.p},${term.q},${term.r})`;
751
+ }
752
+ if (term instanceof NounSentence) {
753
+ return `[${this.interpret(term.expr)}]`;
754
+ }
755
+ if (term instanceof SeqSentence) {
756
+ return `${this.interpret(term.left)} and ${this.interpret(term.right)}`;
757
+ }
758
+ if (term instanceof ImplSentence) {
759
+ return `if ${this.interpret(term.antecedent)} then ${this.interpret(term.consequent)}`;
760
+ }
761
+
762
+ return String(term);
763
+ }
764
+
765
+ /**
766
+ * Add custom concept mappings
767
+ */
768
+ addNounConcept(prime, concept) {
769
+ this.nounConcepts.set(prime, concept);
770
+ }
771
+
772
+ addAdjConcept(prime, concept) {
773
+ this.adjConcepts.set(prime, concept);
774
+ }
775
+ }
776
+
777
+ // ============================================================================
778
+ // TYPE-DIRECTED TRANSLATION
779
+ // ============================================================================
780
+
781
+ /**
782
+ * TypeDirectedTranslator - Translation with type constraints
783
+ */
784
+ class TypeDirectedTranslator extends Translator {
785
+ constructor(operator = DEFAULT_OPERATOR) {
786
+ super(operator);
787
+ }
788
+
789
+ /**
790
+ * Translate with explicit type annotations
791
+ */
792
+ translateTyped(term, context = null) {
793
+ const lambda = this.translate(term);
794
+
795
+ // Annotate with source type information
796
+ return {
797
+ expr: lambda,
798
+ sourceType: term.constructor.name,
799
+ targetType: lambda.getType(),
800
+ context: context
801
+ };
802
+ }
803
+
804
+ /**
805
+ * Check type preservation
806
+ * τ preserves typing: Γ ⊢ e : T implies τ(Γ) ⊢ τ(e) : τ(T)
807
+ */
808
+ checkTypePreservation(term, context = null) {
809
+ const translation = this.translateTyped(term, context);
810
+
811
+ // Verify the translated type matches expected
812
+ return {
813
+ preserved: translation.targetType !== null,
814
+ source: translation.sourceType,
815
+ target: translation.targetType
816
+ };
817
+ }
818
+ }
819
+
820
+ // ============================================================================
821
+ // EXPORTS
822
+ // ============================================================================
823
+
824
+ module.exports = {
825
+ // Lambda expressions
826
+ LambdaExpr,
827
+ VarExpr,
828
+ ConstExpr,
829
+ LamExpr,
830
+ AppExpr,
831
+ PairExpr,
832
+ ImplExpr,
833
+ PrimOpExpr,
834
+
835
+ // Translator
836
+ Translator,
837
+ TypeDirectedTranslator,
838
+
839
+ // Evaluator
840
+ LambdaEvaluator,
841
+
842
+ // Semantics
843
+ Semantics,
844
+ ConceptInterpreter
845
+ };