eyeling 1.33.6 → 1.33.7

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.
Files changed (30) hide show
  1. package/README.md +1 -1
  2. package/docs/eyelang-guide.md +7 -8
  3. package/docs/eyelang-language-reference.md +11 -9
  4. package/examples/eyelang/annotation.pl +9 -9
  5. package/examples/eyelang/context-association.pl +3 -3
  6. package/examples/eyelang/delfour.pl +7 -7
  7. package/examples/eyelang/dijkstra-risk-path.pl +2 -2
  8. package/examples/eyelang/dijkstra.pl +2 -2
  9. package/examples/eyelang/family-cousins.pl +1 -1
  10. package/examples/eyelang/gps.pl +4 -4
  11. package/examples/eyelang/odrl-dpv-healthcare-risk-ranked.pl +2 -2
  12. package/examples/eyelang/odrl-dpv-risk-ranked.pl +2 -2
  13. package/examples/eyelang/proof/annotation.pl +12 -12
  14. package/examples/eyelang/resilient-city-orchestration.pl +5 -5
  15. package/lib/eyelang/builtins/context.js +42 -0
  16. package/lib/eyelang/builtins/registry.js +2 -2
  17. package/package.json +1 -1
  18. package/test/eyelang/conformance/README.md +1 -1
  19. package/test/eyelang/conformance/cases/extension/006_holds_parts.pl +4 -0
  20. package/test/eyelang/conformance/cases/extension/026_nested_holds_parts.pl +4 -0
  21. package/test/eyelang/conformance/cases/extension/027_formula_member.query +1 -0
  22. package/test/eyelang/conformance/cases/extension/027_holds_member.pl +3 -0
  23. package/test/eyelang/conformance/expected/extension/006_holds_parts.out +3 -0
  24. package/test/eyelang/conformance/expected/extension/026_nested_holds_parts.out +3 -0
  25. package/test/eyelang/conformance/expected/extension/027_holds_member.out +2 -0
  26. package/lib/eyelang/builtins/formula.js +0 -26
  27. package/test/eyelang/conformance/cases/extension/006_formula_terms.pl +0 -4
  28. package/test/eyelang/conformance/cases/extension/026_nested_formula_terms.pl +0 -4
  29. package/test/eyelang/conformance/expected/extension/006_formula_terms.out +0 -2
  30. package/test/eyelang/conformance/expected/extension/026_nested_formula_terms.out +0 -3
package/README.md CHANGED
@@ -828,7 +828,7 @@ The eyelang engine has its own built-in registry under `lib/eyelang/builtins/`.
828
828
  | Lists | `append/3`, `nth0/3`, `set_nth0/4`, `rest/2`, `member/2`, `select/3`, `not_member/2`, `reverse/2`, `length/2`, `sort/2` |
829
829
  | Aggregation | `findall/3`, `countall/2`, `sumall/3`, `aggregate_min/5`, `aggregate_max/5` |
830
830
  | Control | `not/1`, `once/1` |
831
- | Formula terms | `formula_binary/4` |
831
+ | Context terms | `holds/2`, `holds/3` |
832
832
  | Search and optimization helpers | `n_queens/2`, `weighted_hamiltonian_cycle/4`, `weighted_hamiltonian_path/4`, `hamiltonian_cycle/3`, `fixed_length_cycle/4`, `bounded_path/5`, `bounded_subset/7`, `cnf_model/3`, `qm_prime_implicants/4`, `qm_minimal_cover/4`, `alphametic_sum/5` |
833
833
  | Numeric extension helpers | `extended_gcd/5`, `collatz_trajectory/2`, `kaprekar_steps/2`, `goldbach_pair/3` |
834
834
  | Matrix helpers | `matrix_sum/2`, `matrix_multiply/2`, `cholesky_decomposition/2`, `determinant/2`, `matrix_inv_triang/2`, `matrix_inversion/2` |
@@ -16,7 +16,7 @@ For the normative language definition, including lexical syntax, terms, clauses,
16
16
  3. [Default output](#default-output)
17
17
  4. [Writing programs](#writing-programs)
18
18
  5. [Aggregation helpers](#aggregation-helpers)
19
- 6. [Formula data](#formula-data)
19
+ 6. [Context data](#context-data)
20
20
  7. [Example catalog](#example-catalog)
21
21
  8. [Golden outputs, tests, and conformance](#golden-outputs-tests-and-conformance)
22
22
  9. [Development and release](#development-and-release)
@@ -250,7 +250,7 @@ The playground has matching `--stats` and `--proof` checkboxes, so browser runs
250
250
 
251
251
  eyelang builtins are registered by name and arity in small modules under [`lib/eyelang/builtins`](../lib/eyelang/builtins). This keeps the runtime portable to Node.js and the browser while giving each builtin family a clear boundary. Builtins are enabled by normal predicate calls.
252
252
 
253
- The core builtin families cover unification, arithmetic, comparison, dates, strings, lists, aggregation, formula terms, and search control. Additional reusable finite-search helpers are available only where bundled examples need them to avoid large amounts of repetitive generate-and-test code. These helpers are deliberately general relations rather than shortcuts tied to a particular example name. For example:
253
+ The core builtin families cover unification, arithmetic, comparison, dates, strings, lists, aggregation, context terms, and search control. Additional reusable finite-search helpers are available only where bundled examples need them to avoid large amounts of repetitive generate-and-test code. These helpers are deliberately general relations rather than shortcuts tied to a particular example name. For example:
254
254
 
255
255
  ```prolog
256
256
  answer(Queens) :-
@@ -287,17 +287,16 @@ best_cycle(Cycle, Cost) :-
287
287
  aggregate_min([Cost, Cycle], Cycle, candidate_cycle(Cities, Cycle, Cost), [Cost, Cycle], Cycle).
288
288
  ```
289
289
 
290
- ## Formula data
290
+ ## Context data
291
291
 
292
- Comma terms can be data as well as conjunctions. eyelang provides a relation-oriented formula utility.
293
-
294
- `formula_binary(Formula, S, P, O)` enumerates binary terms and exposes their functor as an atom constant:
292
+ Comma terms can be data as well as conjunctions. eyelang provides two context utilities:
295
293
 
296
294
  ```prolog
297
- formula_binary((name(alice, "Alice"), knows(alice, bob)), S, P, O).
295
+ holds((name(alice, "Alice"), knows(alice, bob)), name(S, O)).
296
+ holds((ready, name(alice, "Alice"), route(alice, bob, 7)), Name, Args).
298
297
  ```
299
298
 
300
- This can yield `S = alice`, `P = name`, `O = "Alice"` and `S = alice`, `P = knows`, `O = bob`. The utility is useful for quoted formula data, but it does not make those formula members true in the ambient program.
299
+ Use `holds/2` when you want to match the member term directly, for example `name(S, O)`, `route(A, B, Cost)`, or `edge(A, arc(B, Cost))`. Use `holds/3` when you need the predicate name and argument list as data: it exposes any-arity member as atom constant `Name` plus a proper list `Args`, so zero-, binary-, and ternary members appear as `ready/0`, `name/2`, and `route/3` shapes without a special binary predicate. These utilities are useful for quoted context data, but they do not make those context members true in the ambient program.
301
300
 
302
301
 
303
302
  ## Example catalog
@@ -39,7 +39,7 @@
39
39
  - [9.6 Strings and atom constants](#96-strings-and-atom-constants)
40
40
  - [9.7 Lists](#97-lists)
41
41
  - [9.8 Aggregation and ordering](#98-aggregation-and-ordering)
42
- - [9.9 Formula terms](#99-formula-terms)
42
+ - [9.9 Context terms](#99-context-terms)
43
43
  - [9.10 Search control](#910-search-control)
44
44
  - [10. Extension built-ins](#10-extension-built-ins)
45
45
  - [11. Declarations](#11-declarations)
@@ -67,7 +67,7 @@
67
67
 
68
68
  eyelang is a compact Prolog-like definite-clause language for rule-based programs over ordinary terms, lists, arithmetic, strings, and finite search. An eyelang program is a finite sequence of facts and Horn clauses. The underlying declarative semantics of the pure language is **Herbrand semantics**: constants, compound terms, and lists denote themselves, and predicates denote sets of ground atomic formulas over those terms. Evaluation is goal-directed: goals are solved by unification against facts, rules, and a fixed set of built-in predicates.
69
69
 
70
- eyelang is intentionally smaller than ISO Prolog. It supports enough Prolog syntax to express Horn-clause reasoning, list processing, arithmetic examples, finite search, and formula data, without operators, cut, modules, dynamic predicates, DCGs, or a complete ISO standard library.
70
+ eyelang is intentionally smaller than ISO Prolog. It supports enough Prolog syntax to express Horn-clause reasoning, list processing, arithmetic examples, finite search, and context data, without operators, cut, modules, dynamic predicates, DCGs, or a complete ISO standard library.
71
71
 
72
72
  ## 1. Terminology and normative language
73
73
 
@@ -96,7 +96,7 @@ eyelang is designed to be:
96
96
  - small enough to embed and audit;
97
97
  - deterministic in textual output order after duplicate suppression;
98
98
  - useful for relation-style `p(S, O)` output through ordinary predicate names;
99
- - practical for examples involving recursion, lists, arithmetic, strings, aggregation, finite search, and formula-valued data.
99
+ - practical for examples involving recursion, lists, arithmetic, strings, aggregation, finite search, and context-valued data.
100
100
 
101
101
  Non-goals include complete ISO Prolog compatibility, operator declarations, module systems, dynamic database updates, cut-based control, and full bottom-up closure semantics.
102
102
 
@@ -252,7 +252,7 @@ Parenthesized comma terms may be goals or data:
252
252
  (name(alice, "Alice"), knows(alice, bob))
253
253
  ```
254
254
 
255
- When a comma term appears as a goal, it is evaluated as conjunction. When it appears as data, it remains a term. `formula_binary/4` enumerates binary members inside such formula terms.
255
+ When a comma term appears as a goal, it is evaluated as conjunction. When it appears as data, it remains a term. `holds/2` enumerates member terms inside such contexts, and `holds/3` exposes each member as a predicate name plus an argument list for any arity.
256
256
 
257
257
  ## 6. Clauses and predicates
258
258
 
@@ -429,21 +429,23 @@ Comparisons interpret numeric-looking terms numerically. Other scalar terms are
429
429
  | `aggregate_max(Key, Template, Goal, BestKey, BestTemplate)` | Selects the solution of `Goal` with the largest resolved `Key`, returning that key and the corresponding resolved `Template`. Fails when `Goal` has no solutions. |
430
430
  | `sort(Input, Output)` | Sorts and deduplicates a proper list. |
431
431
 
432
- ### 9.9 Formula terms
432
+ ### 9.9 Context terms
433
433
 
434
- Formula terms are data representations of atomic formulas and comma conjunctions.
434
+ Context terms are data representations of atomic formulas and comma conjunctions.
435
435
 
436
436
  | Built-in | Meaning |
437
437
  |---|---|
438
- | `formula_binary(Formula, S, P, O)` | Enumerates binary formula members `P(S, O)`, exposing the functor as atom constant `P`. |
438
+ | `holds(Context, Term)` | Enumerates member terms inside a context term and unifies each member with `Term`. |
439
+ | `holds(Context, Name, Args)` | Enumerates context members of any arity, exposing each member as atom constant `Name` plus a proper argument list `Args`. |
439
440
 
440
441
  Example:
441
442
 
442
443
  ```prolog
443
- formula_binary((name(alice, "Alice"), knows(alice, bob)), S, P, O).
444
+ holds((name(alice, "Alice"), knows(alice, bob)), name(S, O)).
445
+ holds((ready, name(alice, "Alice"), route(alice, bob, 7)), Name, Args).
444
446
  ```
445
447
 
446
- This can yield `formula_binary((name(alice, "Alice"), knows(alice, bob)), alice, name, "Alice").` and `formula_binary((name(alice, "Alice"), knows(alice, bob)), alice, knows, bob).`
448
+ The first goal can yield `holds((name(alice, "Alice"), knows(alice, bob)), name(alice, "Alice")).` The second can yield `holds((ready, name(alice, "Alice"), route(alice, bob, 7)), ready, []).`, `holds((ready, name(alice, "Alice"), route(alice, bob, 7)), name, [alice, "Alice"]).`, and `holds((ready, name(alice, "Alice"), route(alice, bob, 7)), route, [alice, bob, 7]).`
447
449
 
448
450
  ### 9.10 Search control
449
451
 
@@ -1,7 +1,7 @@
1
1
  % Annotation with quoted formula data.
2
2
  %
3
3
  % The program keeps the annotation as data and derives visible relations from it.
4
- % Formula members become default output only when explicit rules project them.
4
+ % Context members become default output only when explicit rules project them.
5
5
 
6
6
  % Output declarations: materialize/2 selects the relations written to this example's golden output.
7
7
  materialize(name, 2).
@@ -18,17 +18,17 @@ annotation(t, (
18
18
 
19
19
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
20
20
  name(S, O) :-
21
- annotation(_T, Formula),
22
- formula_binary(Formula, S, name, O).
21
+ annotation(_T, Context),
22
+ holds(Context, name(S, O)).
23
23
 
24
24
  log_nameOf(T, name(S, O)) :-
25
- annotation(T, Formula),
26
- formula_binary(Formula, S, name, O).
25
+ annotation(T, Context),
26
+ holds(Context, name(S, O)).
27
27
 
28
28
  statedBy(S, O) :-
29
- annotation(_T, Formula),
30
- formula_binary(Formula, S, statedBy, O).
29
+ annotation(_T, Context),
30
+ holds(Context, statedBy(S, O)).
31
31
 
32
32
  recorded(S, O) :-
33
- annotation(_T, Formula),
34
- formula_binary(Formula, S, recorded, O).
33
+ annotation(_T, Context),
34
+ holds(Context, recorded(S, O)).
@@ -39,9 +39,9 @@ log_nameOf(g3, (
39
39
  % A tiny projection shows how a program can inspect a quoted context without
40
40
  % making the entire context globally true.
41
41
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
42
- context_statement(Context, Subject, Predicate, Object) :-
43
- log_nameOf(Context, Formula),
44
- formula_binary(Formula, Subject, Predicate, Object).
42
+ context_statement(ContextName, Subject, Predicate, Object) :-
43
+ log_nameOf(ContextName, Context),
44
+ holds(Context, Predicate, [Subject, Object]).
45
45
 
46
46
  dataGraph(association, skolem_g0) :-
47
47
  context_statement(skolem_g0, bob, foaf_name, "Bob").
@@ -4,7 +4,7 @@
4
4
  % checklist facts as relation materialization.
5
5
  %
6
6
  % Static input is kept as scoped data: the case, insight, policy, envelope, and
7
- % signature are formula terms, while the product catalog is a list of records.
7
+ % signature are context terms, while the product catalog is a list of records.
8
8
  % Rules project only the fields they need, avoiding global permission/prohibition
9
9
  % facts that could contradict another policy formula in the same program.
10
10
 
@@ -41,7 +41,7 @@ materialize(marketingProhibited, 2).
41
41
  materialize(filesWrittenExpected, 2).
42
42
 
43
43
  % Program structure: facts set up the scenario, and rules derive the materialized conclusions.
44
- % Formula-valued facts keep each input graph scoped and easy to project.
44
+ % Context-valued facts keep each input graph scoped and easy to project.
45
45
  case_graph(delfourCaseGraph, (
46
46
  caseName(case, "delfour"),
47
47
  requestPurpose(case, "shopping_assist"),
@@ -102,11 +102,11 @@ signature_graph(delfourSignatureGraph, (
102
102
  reason_text(reasonText, "Household requires low-sugar guidance (diabetes in POD). A neutral Insight is scoped to device 'self-scanner', event 'pick_up_scanner', retailer 'Delfour', and expires soon; the policy confines use to shopping assistance.").
103
103
 
104
104
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
105
- case_statement(S, P, O) :- case_graph(delfourCaseGraph, Formula), formula_binary(Formula, S, P, O).
106
- insight_statement(S, P, O) :- insight_graph(delfourInsightGraph, Formula), formula_binary(Formula, S, P, O).
107
- policy_statement(S, P, O) :- policy_graph(delfourPolicyGraph, Formula), formula_binary(Formula, S, P, O).
108
- envelope_statement(S, P, O) :- envelope_graph(delfourEnvelopeGraph, Formula), formula_binary(Formula, S, P, O).
109
- signature_statement(S, P, O) :- signature_graph(delfourSignatureGraph, Formula), formula_binary(Formula, S, P, O).
105
+ case_statement(S, P, O) :- case_graph(delfourCaseGraph, Context), holds(Context, P, [S, O]).
106
+ insight_statement(S, P, O) :- insight_graph(delfourInsightGraph, Context), holds(Context, P, [S, O]).
107
+ policy_statement(S, P, O) :- policy_graph(delfourPolicyGraph, Context), holds(Context, P, [S, O]).
108
+ envelope_statement(S, P, O) :- envelope_graph(delfourEnvelopeGraph, Context), holds(Context, P, [S, O]).
109
+ signature_statement(S, P, O) :- signature_graph(delfourSignatureGraph, Context), holds(Context, P, [S, O]).
110
110
 
111
111
  case_name(case, Name) :- case_statement(case, caseName, Name).
112
112
  request_purpose(case, Purpose) :- case_statement(case, requestPurpose, Purpose).
@@ -32,8 +32,8 @@ route_network(riskNetwork, (
32
32
 
33
33
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
34
34
  route_segment(From, To, Raw, Risk) :-
35
- route_network(riskNetwork, Formula),
36
- formula_binary(Formula, From, segment, segment(To, Raw, Risk)).
35
+ route_network(riskNetwork, Context),
36
+ holds(Context, segment(From, segment(To, Raw, Risk))).
37
37
 
38
38
  candidate(pathB, [depotA, depotB, labD]).
39
39
  candidate(pathC, [depotA, depotC, labD]).
@@ -24,8 +24,8 @@ weighted_graph(dijkstraGraph, (
24
24
 
25
25
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
26
26
  base_link(A, B, Cost) :-
27
- weighted_graph(dijkstraGraph, Formula),
28
- formula_binary(Formula, A, edge, arc(B, Cost)).
27
+ weighted_graph(dijkstraGraph, Context),
28
+ holds(Context, edge(A, arc(B, Cost))).
29
29
 
30
30
  link(A, B, Cost) :- base_link(A, B, Cost).
31
31
  link(B, A, Cost) :- base_link(A, B, Cost).
@@ -33,7 +33,7 @@ family_graph(familyGraph, (
33
33
  )).
34
34
 
35
35
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
36
- family_statement(S, P, O) :- family_graph(familyGraph, Formula), formula_binary(Formula, S, P, O).
36
+ family_statement(S, P, O) :- family_graph(familyGraph, Context), holds(Context, P, [S, O]).
37
37
 
38
38
  parent(Parent, Child) :- family_statement(Parent, parent, Child).
39
39
  branch(Person, Branch) :- family_statement(Person, seedBranch, Branch).
@@ -39,12 +39,12 @@ map_graph(mapBE, (
39
39
 
40
40
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
41
41
  case_statement(S, P, O) :-
42
- case_graph(caseGraph, Formula),
43
- formula_binary(Formula, S, P, O).
42
+ case_graph(caseGraph, Context),
43
+ holds(Context, P, [S, O]).
44
44
 
45
45
  map_description(From, To, Action, Duration, Cost, Belief, Comfort) :-
46
- map_graph(mapBE, Formula),
47
- formula_binary(Formula, mapBE, gps_description, description(From, true, To, Action, Duration, Cost, Belief, Comfort)).
46
+ map_graph(mapBE, Context),
47
+ holds(Context, gps_description(mapBE, description(From, true, To, Action, Duration, Cost, Belief, Comfort))).
48
48
 
49
49
  path(From, To, [Action], Duration, Cost, Belief, Comfort) :-
50
50
  map_description(From, To, Action, Duration, Cost, Belief, Comfort).
@@ -114,8 +114,8 @@ policy_graph(policyGraphHC1, (
114
114
 
115
115
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
116
116
  policy_statement(GraphName, Subject, Predicate, Object) :-
117
- policy_graph(GraphName, Formula),
118
- formula_binary(Formula, Subject, Predicate, Object).
117
+ policy_graph(GraphName, Context),
118
+ holds(Context, Predicate, [Subject, Object]).
119
119
 
120
120
  permission(Graph, Permission) :- policy_statement(Graph, policyHC1, odrl_permission, Permission).
121
121
  clause(Graph, Permission, Clause) :- policy_statement(Graph, Permission, clause, Clause).
@@ -98,8 +98,8 @@ policy_graph(policyGraph1, (
98
98
 
99
99
  % Derivation rules: each rule below contributes one logical step toward the displayed results.
100
100
  policy_statement(Subject, Predicate, Object) :-
101
- policy_graph(_Graph, Formula),
102
- formula_binary(Formula, Subject, Predicate, Object).
101
+ policy_graph(_Graph, Context),
102
+ holds(Context, Predicate, [Subject, Object]).
103
103
 
104
104
  policy(Policy, Agreement) :- policy_statement(Policy, odrl_appliesTo, Agreement).
105
105
  permission(Policy, Rule) :- policy_statement(Policy, odrl_permission, Rule).
@@ -4,15 +4,15 @@ why(
4
4
  proof(
5
5
  goal(name(a, "Alice")),
6
6
  by(rule("annotation.pl", clause(6))),
7
- bindings([binding("S", a), binding("O", "Alice"), binding("_T", t), binding("Formula", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
7
+ bindings([binding("S", a), binding("O", "Alice"), binding("_T", t), binding("Context", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
8
8
  uses([
9
9
  proof(
10
10
  goal(annotation(t, (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))),
11
11
  by(fact("annotation.pl", clause(5)))
12
12
  ),
13
13
  proof(
14
- goal(formula_binary((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), a, name, "Alice")),
15
- by(builtin(formula_binary, 4))
14
+ goal(holds((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), name(a, "Alice"))),
15
+ by(builtin(holds, 2))
16
16
  )
17
17
  ])
18
18
  )
@@ -24,15 +24,15 @@ why(
24
24
  proof(
25
25
  goal(log_nameOf(t, name(a, "Alice"))),
26
26
  by(rule("annotation.pl", clause(7))),
27
- bindings([binding("T", t), binding("S", a), binding("O", "Alice"), binding("Formula", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
27
+ bindings([binding("T", t), binding("S", a), binding("O", "Alice"), binding("Context", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
28
28
  uses([
29
29
  proof(
30
30
  goal(annotation(t, (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))),
31
31
  by(fact("annotation.pl", clause(5)))
32
32
  ),
33
33
  proof(
34
- goal(formula_binary((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), a, name, "Alice")),
35
- by(builtin(formula_binary, 4))
34
+ goal(holds((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), name(a, "Alice"))),
35
+ by(builtin(holds, 2))
36
36
  )
37
37
  ])
38
38
  )
@@ -44,15 +44,15 @@ why(
44
44
  proof(
45
45
  goal(statedBy(t, bob)),
46
46
  by(rule("annotation.pl", clause(8))),
47
- bindings([binding("S", t), binding("O", bob), binding("_T", t), binding("Formula", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
47
+ bindings([binding("S", t), binding("O", bob), binding("_T", t), binding("Context", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
48
48
  uses([
49
49
  proof(
50
50
  goal(annotation(t, (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))),
51
51
  by(fact("annotation.pl", clause(5)))
52
52
  ),
53
53
  proof(
54
- goal(formula_binary((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), t, statedBy, bob)),
55
- by(builtin(formula_binary, 4))
54
+ goal(holds((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), statedBy(t, bob))),
55
+ by(builtin(holds, 2))
56
56
  )
57
57
  ])
58
58
  )
@@ -64,15 +64,15 @@ why(
64
64
  proof(
65
65
  goal(recorded(t, "2021-07-07")),
66
66
  by(rule("annotation.pl", clause(9))),
67
- bindings([binding("S", t), binding("O", "2021-07-07"), binding("_T", t), binding("Formula", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
67
+ bindings([binding("S", t), binding("O", "2021-07-07"), binding("_T", t), binding("Context", (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))]),
68
68
  uses([
69
69
  proof(
70
70
  goal(annotation(t, (name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")))),
71
71
  by(fact("annotation.pl", clause(5)))
72
72
  ),
73
73
  proof(
74
- goal(formula_binary((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), t, recorded, "2021-07-07")),
75
- by(builtin(formula_binary, 4))
74
+ goal(holds((name(a, "Alice"), statedBy(t, bob), recorded(t, "2021-07-07")), recorded(t, "2021-07-07"))),
75
+ by(builtin(holds, 2))
76
76
  )
77
77
  ])
78
78
  )
@@ -45,7 +45,7 @@ reading(substation_load_percent, 94).
45
45
  threshold(substation_load_percent, 85).
46
46
 
47
47
  % The deployable skills are stored as quoted formula data and projected by
48
- % formula_binary/4, showing how policy documents can be reasoned over as data.
48
+ % holds/2, showing how policy documents can be reasoned over as data.
49
49
  policy_bundle(response_policy, (
50
50
  permission(medical_transport, deploy),
51
51
  permission(cold_chain, deploy),
@@ -168,13 +168,13 @@ criticalNeed(civic_storm, map_flood_front) :-
168
168
  activeSignal(civic_storm, river_surge).
169
169
 
170
170
  policyClearance(Skill, deploy) :-
171
- policy_bundle(response_policy, Formula),
172
- formula_binary(Formula, Skill, permission, deploy),
171
+ policy_bundle(response_policy, Context),
172
+ holds(Context, permission(Skill, deploy)),
173
173
  not(policyBlocked(Skill, deploy)).
174
174
 
175
175
  policyBlocked(Skill, deploy) :-
176
- policy_bundle(response_policy, Formula),
177
- formula_binary(Formula, Skill, prohibition, deploy).
176
+ policy_bundle(response_policy, Context),
177
+ holds(Context, prohibition(Skill, deploy)).
178
178
 
179
179
  usableRoute(Zone, route(Path, minutes(Minutes), risk(RouteRisk))) :-
180
180
  zone(Zone),
@@ -0,0 +1,42 @@
1
+ // Context builtins that treat comma conjunctions as first-class data terms.
2
+ // These are used by examples that construct or inspect rule bodies programmatically.
3
+ import { atom, deref, isConjunction, listFromItems, unify } from '../term.js';
4
+
5
+ export const contextBuiltins = {
6
+ register(registry) {
7
+ registry.add('holds', 2, holdsTerm);
8
+ registry.add('holds', 3, holdsParts);
9
+ }
10
+ };
11
+
12
+ function* emitContextTerm(context, term, env) {
13
+ context = deref(context, env);
14
+ if (isConjunction(context)) {
15
+ yield* emitContextTerm(context.args[0], term, env);
16
+ yield* emitContextTerm(context.args[1], term, env);
17
+ return;
18
+ }
19
+ const next = env.clone();
20
+ if (unify(term, context, next)) yield next;
21
+ }
22
+
23
+ function* emitContextParts(context, name, args, env) {
24
+ context = deref(context, env);
25
+ if (isConjunction(context)) {
26
+ yield* emitContextParts(context.args[0], name, args, env);
27
+ yield* emitContextParts(context.args[1], name, args, env);
28
+ return;
29
+ }
30
+ if (context.type !== 'atom' && context.type !== 'compound') return;
31
+ const next = env.clone();
32
+ const argList = context.type === 'compound' ? listFromItems(context.args) : listFromItems([]);
33
+ if (unify(name, atom(context.name), next) && unify(args, argList, next)) yield next;
34
+ }
35
+
36
+ function* holdsTerm({ goal, env }) {
37
+ yield* emitContextTerm(goal.args[0], goal.args[1], env);
38
+ }
39
+
40
+ function* holdsParts({ goal, env }) {
41
+ yield* emitContextParts(goal.args[0], goal.args[1], goal.args[2], env);
42
+ }
@@ -5,7 +5,7 @@ import { coreBuiltins } from './core.js';
5
5
  import { stringBuiltins } from './strings.js';
6
6
  import { listBuiltins } from './lists.js';
7
7
  import { aggregationBuiltins } from './aggregation.js';
8
- import { formulaBuiltins } from './formula.js';
8
+ import { contextBuiltins } from './context.js';
9
9
  import { controlBuiltins } from './control.js';
10
10
  import { portfolioBuiltins } from './portfolio.js';
11
11
  import { searchBuiltins } from './search.js';
@@ -38,7 +38,7 @@ export class BuiltinRegistry {
38
38
 
39
39
  export function createDefaultRegistry() {
40
40
  const registry = new BuiltinRegistry();
41
- for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, formulaBuiltins, controlBuiltins, portfolioBuiltins, searchBuiltins, numberTheoryBuiltins, matrixBuiltins, alphameticBuiltins]) {
41
+ for (const mod of [coreBuiltins, arithmeticBuiltins, stringBuiltins, listBuiltins, aggregationBuiltins, contextBuiltins, controlBuiltins, portfolioBuiltins, searchBuiltins, numberTheoryBuiltins, matrixBuiltins, alphameticBuiltins]) {
42
42
  mod.register(registry);
43
43
  }
44
44
  return registry;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyeling",
3
- "version": "1.33.6",
3
+ "version": "1.33.7",
4
4
  "description": "A minimal Notation3 (N3) reasoner in JavaScript.",
5
5
  "main": "./index.js",
6
6
  "keywords": [
@@ -36,7 +36,7 @@ The runner executes materialized programs in-process through the public JavaScri
36
36
 
37
37
  `core` covers the portable core language profile from the [eyelang language reference](../../../docs/eyelang-language-reference.md): lexical syntax, facts, definite clauses, first-order terms, lists, conjunction, structured unification through user predicates, left-to-right goal-directed proof search, materialized output, and read-back printing.
38
38
 
39
- `extension` covers the standard built-in and host behavior exercised by the current reference implementation: arithmetic, comparison, strings, list relations, aggregation, formula-term helpers, number-theory helpers, finite-search helpers used by the example corpus, matrix helpers, `memoize/2`, `materialize/2`, and default derived output.
39
+ `extension` covers the standard built-in and host behavior exercised by the current reference implementation: arithmetic, comparison, strings, list relations, aggregation, context-term helpers, number-theory helpers, finite-search helpers used by the example corpus, matrix helpers, `memoize/2`, `materialize/2`, and default derived output.
40
40
 
41
41
  The profile name `extension` is a test-suite grouping name. It does not mean that these cases are outside the eyelang language reference; most of them correspond to the standard built-in profile and standard host profile in the [eyelang language reference](../../../docs/eyelang-language-reference.md).
42
42
 
@@ -0,0 +1,4 @@
1
+ % Reference 9.9: holds/3 exposes context members of any arity.
2
+ context((ready, name(alice, "Alice"), route(alice, bob, 7))).
3
+ answer(parts, exposed(Name, Args)) :- context(C), holds(C, Name, Args).
4
+ materialize(answer, 2).
@@ -0,0 +1,4 @@
1
+ % Reference 9.9: holds/3 enumerates nested comma contexts.
2
+ context(((ready, name(a, "A")), route(a, b, 7))).
3
+ answer(parts, exposed(Name, Args)) :- context(C), holds(C, Name, Args).
4
+ materialize(answer, 2).
@@ -0,0 +1,3 @@
1
+ % Reference 9.9: holds/2 over comma context data.
2
+ context((name(alice, "Alice"), knows(alice, bob))).
3
+ answer(member, Term) :- context(C), holds(C, Term).
@@ -0,0 +1,3 @@
1
+ answer(parts, exposed(ready, [])).
2
+ answer(parts, exposed(name, [alice, "Alice"])).
3
+ answer(parts, exposed(route, [alice, bob, 7])).
@@ -0,0 +1,3 @@
1
+ answer(parts, exposed(ready, [])).
2
+ answer(parts, exposed(name, [a, "A"])).
3
+ answer(parts, exposed(route, [a, b, 7])).
@@ -0,0 +1,2 @@
1
+ answer(member, name(alice, "Alice")).
2
+ answer(member, knows(alice, bob)).
@@ -1,26 +0,0 @@
1
- // Formula builtins that treat conjunctions as first-class data terms.
2
- // These are used by examples that construct or inspect rule bodies programmatically.
3
- import { atom, deref, isConjunction, unify } from '../term.js';
4
-
5
- export const formulaBuiltins = {
6
- register(registry) {
7
- registry.add('formula_binary', 4, formulaBinary);
8
- }
9
- };
10
-
11
-
12
- function* emitFormulaBinary(formula, subject, predicate, object, env) {
13
- formula = deref(formula, env);
14
- if (isConjunction(formula)) {
15
- yield* emitFormulaBinary(formula.args[0], subject, predicate, object, env);
16
- yield* emitFormulaBinary(formula.args[1], subject, predicate, object, env);
17
- return;
18
- }
19
- if (formula.type !== 'compound' || formula.arity !== 2) return;
20
- const next = env.clone();
21
- if (unify(subject, formula.args[0], next) && unify(predicate, atom(formula.name), next) && unify(object, formula.args[1], next)) yield next;
22
- }
23
-
24
- function* formulaBinary({ goal, env }) {
25
- yield* emitFormulaBinary(goal.args[0], goal.args[1], goal.args[2], goal.args[3], env);
26
- }
@@ -1,4 +0,0 @@
1
- % Reference 9.9: formula_binary/4 over comma formula data.
2
- formula((name(alice, "Alice"), knows(alice, bob))).
3
- answer(binary, exposed(S, P, O)) :- formula(F), formula_binary(F, S, P, O).
4
- materialize(answer, 2).
@@ -1,4 +0,0 @@
1
- % Reference 9.9: formula helpers enumerate nested comma formula members.
2
- formula(((name(a, "A"), knows(a, b)), likes(b, c))).
3
- answer(binary, exposed(S, P, O)) :- formula(F), formula_binary(F, S, P, O).
4
- materialize(answer, 2).
@@ -1,2 +0,0 @@
1
- answer(binary, exposed(alice, name, "Alice")).
2
- answer(binary, exposed(alice, knows, bob)).
@@ -1,3 +0,0 @@
1
- answer(binary, exposed(a, name, "A")).
2
- answer(binary, exposed(a, knows, b)).
3
- answer(binary, exposed(b, likes, c)).