eyelang 1.4.0 → 1.5.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/README.md +22 -43
- package/SPEC.md +16 -16
- package/bin/eyelang +0 -0
- package/conformance/README.md +4 -5
- package/conformance/cases/core/001_fact_output.pl +4 -0
- package/conformance/cases/core/002_rule_recursion.pl +4 -2
- package/conformance/cases/core/003_terms_and_readback.pl +15 -13
- package/conformance/cases/core/004_conjunction_and_parentheses.pl +1 -0
- package/conformance/cases/core/005_list_deconstruction.pl +1 -0
- package/conformance/cases/core/006_comma_formula_data.pl +1 -0
- package/conformance/cases/core/007_anonymous_variables.pl +1 -0
- package/conformance/cases/core/008_graphic_atoms.pl +5 -3
- package/conformance/cases/core/009_comments_and_whitespace.pl +1 -0
- package/conformance/cases/core/010_variable_scope_and_reuse.pl +1 -0
- package/conformance/cases/core/011_predicate_arity.pl +1 -0
- package/conformance/cases/core/012_nested_compound_unification.pl +1 -0
- package/conformance/cases/core/013_multiple_clauses_order.pl +1 -0
- package/conformance/cases/core/014_failure_filters_answers.pl +2 -0
- package/conformance/cases/core/015_improper_list_unification.pl +1 -0
- package/conformance/cases/core/016_zero_arity_compound.pl +1 -0
- package/conformance/cases/core/017_three_step_recursion.pl +1 -0
- package/conformance/cases/core/018_quoted_atom_readback.pl +1 -0
- package/conformance/cases/core/019_parenthesized_three_conjuncts.pl +1 -0
- package/conformance/cases/core/020_nested_list_terms.pl +1 -0
- package/conformance/cases/extension/001_default_derived_output.pl +1 -1
- package/conformance/cases/extension/002_materialize_focus.pl +1 -1
- package/conformance/cases/extension/003_arithmetic_and_comparison.pl +1 -0
- package/conformance/cases/extension/004_strings_and_atoms.pl +1 -0
- package/conformance/cases/extension/005_lists_aggregation_ordering.pl +1 -0
- package/conformance/cases/extension/006_formula_terms.pl +1 -0
- package/conformance/cases/extension/007_negation_once_generators.pl +1 -0
- package/conformance/cases/extension/008_equality_and_inequality.pl +1 -0
- package/conformance/cases/extension/009_list_relations.pl +1 -0
- package/conformance/cases/extension/010_append_splits.pl +1 -0
- package/conformance/cases/extension/011_matching_and_comparison.pl +1 -0
- package/conformance/cases/extension/012_memoize_declaration.pl +5 -3
- package/conformance/cases/extension/013_numeric_functions.pl +1 -0
- package/conformance/cases/extension/014_between_enumeration.pl +1 -0
- package/conformance/cases/extension/015_smallest_divisor.pl +1 -0
- package/conformance/cases/extension/016_negation_filter.pl +1 -0
- package/conformance/cases/extension/017_once_user_predicate.pl +1 -0
- package/conformance/cases/extension/018_findall_user_goal.pl +1 -0
- package/conformance/cases/extension/019_sort_deduplicates_atoms.pl +1 -0
- package/conformance/cases/extension/020_append_bound_prefix_suffix.pl +1 -0
- package/conformance/cases/extension/021_nth0_index_generation.pl +1 -0
- package/conformance/cases/extension/022_set_nth0_edges.pl +1 -0
- package/conformance/cases/extension/023_select_duplicate_occurrences.pl +1 -0
- package/conformance/cases/extension/024_not_member_filter.pl +1 -0
- package/conformance/cases/extension/025_is_list_filter.pl +1 -0
- package/conformance/cases/extension/026_nested_formula_terms.pl +1 -0
- package/conformance/cases/extension/027_materialize_excludes_source_fact.pl +1 -1
- package/conformance/cases/extension/028_numeric_and_lexical_comparison.pl +1 -0
- package/conformance/cases/extension/029_string_matching_filters.pl +1 -0
- package/conformance/cases/extension/030_string_and_atom_concat.pl +1 -0
- package/conformance/cases/extension/031_countall_empty_and_nonempty.pl +2 -0
- package/conformance/cases/extension/032_sumall_numeric_template.pl +2 -0
- package/conformance/cases/extension/033_aggregate_min_template.pl +2 -0
- package/conformance/cases/extension/034_aggregate_max_compound_key.pl +2 -0
- package/conformance/expected/extension/031_countall_empty_and_nonempty.out +1 -1
- package/conformance/expected/extension/032_sumall_numeric_template.out +1 -1
- package/conformance/expected/extension/033_aggregate_min_template.out +1 -1
- package/conformance/expected/extension/034_aggregate_max_compound_key.out +1 -1
- package/examples/basic-monadic.pl +1 -1
- package/examples/monkey-bananas.pl +1 -1
- package/examples/path-discovery.pl +3 -3
- package/examples/peano-arithmetic.pl +1 -1
- package/package.json +1 -1
- package/playground-worker.mjs +2 -15
- package/playground.html +5 -25
- package/src/builtins/aggregation.js +5 -5
- package/src/builtins/control.js +3 -3
- package/src/builtins/registry.js +7 -0
- package/src/cli.js +36 -38
- package/src/index.js +21 -28
- package/src/parser.js +3 -3
- package/src/solver.js +2 -2
- package/test/run-conformance.js +20 -45
- package/test/run-examples.js +42 -50
- package/test/run-regression.js +38 -59
- package/conformance/cases/core/001_fact_query.pl +0 -2
- /package/conformance/expected/core/{001_fact_query.out → 001_fact_output.out} +0 -0
package/README.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
|
|
6
6
|
eyelang is a small rule engine for Prolog-style Horn clauses over ordinary terms, lists, arithmetic, strings, and finite search. The command-line executable is `eyelang`.
|
|
7
7
|
|
|
8
|
-
Programs write relations directly, for example `ancestor(pat, emma)` or `status(case1, accepted)`. eyelang output is ordinary eyelang syntax: by default,
|
|
8
|
+
Programs write relations directly, for example `ancestor(pat, emma)` or `status(case1, accepted)`. eyelang output is ordinary eyelang syntax: by default, the CLI materializes selected answer facts and prints those facts only. Pass `--proof` (or `-p`) when you also want each answer followed by a `why/2` explanation fact that records the proof. Programs may add `materialize(Name, Arity).` declarations to focus output on selected predicates.
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
Try it in the [browser playground](https://eyereasoner.github.io/eyelang/playground). The playground includes run options equivalent to CLI `--
|
|
11
|
+
Try it in the [browser playground](https://eyereasoner.github.io/eyelang/playground). The playground includes run options equivalent to CLI `--stats` and `--proof`.
|
|
12
12
|
|
|
13
13
|
For the normative language definition, including lexical syntax, terms, clauses, goals, built-ins, `memoize/2`, `materialize/2`, and conformance boundaries, read the [eyelang specification](SPEC.md).
|
|
14
14
|
|
|
@@ -34,12 +34,11 @@ Install dependencies, if any, and run the command-line executable:
|
|
|
34
34
|
npm install
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
There is no build step for the CLI. Run examples,
|
|
37
|
+
There is no build step for the CLI. Run examples, multiple inputs, stdin, or a URL:
|
|
38
38
|
|
|
39
39
|
```sh
|
|
40
40
|
bin/eyelang --version
|
|
41
41
|
bin/eyelang examples/ancestor.pl
|
|
42
|
-
bin/eyelang --query 'ancestor(pat, X)' examples/ancestor.pl
|
|
43
42
|
bin/eyelang facts.pl rules.pl
|
|
44
43
|
printf 'works(stdin, true) :- eq(ok, ok).\n' | bin/eyelang -
|
|
45
44
|
bin/eyelang https://raw.githubusercontent.com/eyereasoner/eyelang/refs/heads/main/examples/ancestor.pl
|
|
@@ -69,20 +68,14 @@ Run a program and let eyelang print derived binary facts:
|
|
|
69
68
|
bin/eyelang examples/ancestor.pl
|
|
70
69
|
```
|
|
71
70
|
|
|
72
|
-
Run an explicit query:
|
|
73
|
-
|
|
74
|
-
```sh
|
|
75
|
-
bin/eyelang --query 'ancestor(pat, X)' examples/ancestor.pl
|
|
76
|
-
```
|
|
77
|
-
|
|
78
71
|
Enable proof explanations when you want machine-readable provenance:
|
|
79
72
|
|
|
80
73
|
```sh
|
|
81
|
-
bin/eyelang --proof
|
|
74
|
+
bin/eyelang --proof examples/ancestor.pl
|
|
82
75
|
bin/eyelang -p examples/ancestor.pl
|
|
83
76
|
```
|
|
84
77
|
|
|
85
|
-
eyelang-readable explanations are opt-in proof output. Each `why/2` fact contains a nested abstract proof term, and a blank line separates consecutive explanations. Using eyelang syntax for explanations keeps them in the same language as the answers themselves: they are readable by humans, parseable by eyelang, easy to test, and can be
|
|
78
|
+
eyelang-readable explanations are opt-in proof output. Each `why/2` fact contains a nested abstract proof term, and a blank line separates consecutive explanations. Using eyelang syntax for explanations keeps them in the same language as the answers themselves: they are readable by humans, parseable by eyelang, easy to test, and can be transformed or explained further like any other eyelang data. For example:
|
|
86
79
|
|
|
87
80
|
```prolog
|
|
88
81
|
type(socrates, mortal).
|
|
@@ -103,7 +96,7 @@ why(
|
|
|
103
96
|
|
|
104
97
|
```
|
|
105
98
|
|
|
106
|
-
The explanation output can itself be read as eyelang input
|
|
99
|
+
The explanation output can itself be read as eyelang input; for example, another program can materialize `why/2` facts such as `why(type(socrates, mortal), Proof)`. `--proof` adds only these explanation facts; it does not change the answers found by the solver.
|
|
107
100
|
|
|
108
101
|
### Explanation cookbook
|
|
109
102
|
|
|
@@ -112,7 +105,7 @@ eyelang answers can carry their own provenance when proof output is enabled.
|
|
|
112
105
|
Explain one derived fact:
|
|
113
106
|
|
|
114
107
|
```sh
|
|
115
|
-
bin/eyelang --proof
|
|
108
|
+
bin/eyelang --proof examples/socrates.pl
|
|
116
109
|
```
|
|
117
110
|
|
|
118
111
|
The output contains the answer and a `why/2` fact. The proof term shows the source rule that produced the answer and the source fact used below it. Source references use `rule("file.pl", clause(N))` and `fact("file.pl", clause(N))`, where `N` is the 1-based clause number in that file.
|
|
@@ -130,7 +123,7 @@ status(Case, accepted) :-
|
|
|
130
123
|
```
|
|
131
124
|
|
|
132
125
|
```sh
|
|
133
|
-
bin/eyelang --
|
|
126
|
+
bin/eyelang --proof policy.pl
|
|
134
127
|
```
|
|
135
128
|
|
|
136
129
|
The explanation contains the instantiated answer and the variables that made the rule succeed:
|
|
@@ -153,12 +146,10 @@ Use the `uses([...])` list to follow the proof tree. In the policy example it co
|
|
|
153
146
|
Reuse explanations as data:
|
|
154
147
|
|
|
155
148
|
```sh
|
|
156
|
-
bin/eyelang --proof
|
|
157
|
-
bin/eyelang --query 'why(type(socrates, mortal), Proof)' socrates.why.pl
|
|
149
|
+
bin/eyelang --proof examples/socrates.pl > socrates.why.pl
|
|
158
150
|
```
|
|
159
151
|
|
|
160
|
-
|
|
161
|
-
|
|
152
|
+
The resulting file is ordinary eyelang syntax containing both answers and `why/2` proof facts.
|
|
162
153
|
|
|
163
154
|
Compose multiple files, stdin, and URLs:
|
|
164
155
|
|
|
@@ -168,12 +159,6 @@ printf 'works(stdin, true) :- eq(ok, ok).\n' | bin/eyelang -
|
|
|
168
159
|
bin/eyelang https://example.test/program.pl
|
|
169
160
|
```
|
|
170
161
|
|
|
171
|
-
`--query GOAL` parses a single goal. Parenthesized conjunctions are accepted:
|
|
172
|
-
|
|
173
|
-
```sh
|
|
174
|
-
bin/eyelang --query '(ancestor(pat, X), ancestor(X, emma))' examples/ancestor.pl
|
|
175
|
-
```
|
|
176
|
-
|
|
177
162
|
## Default output
|
|
178
163
|
|
|
179
164
|
eyelang programs write relation predicates directly:
|
|
@@ -186,7 +171,7 @@ ancestor(X, Y) :- parent(X, Y).
|
|
|
186
171
|
ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).
|
|
187
172
|
```
|
|
188
173
|
|
|
189
|
-
|
|
174
|
+
By default, eyelang asks for new ground consequences of selected output predicates, suppresses duplicates, excludes source facts, sorts the result, and prints Prolog facts:
|
|
190
175
|
|
|
191
176
|
```prolog
|
|
192
177
|
ancestor(jan, emma).
|
|
@@ -194,11 +179,11 @@ ancestor(pat, emma).
|
|
|
194
179
|
ancestor(pat, jan).
|
|
195
180
|
```
|
|
196
181
|
|
|
197
|
-
This default is intentionally output-oriented. It is not a complete bottom-up saturation engine. Built-ins and proof search remain goal-directed; use
|
|
182
|
+
This default is intentionally output-oriented. It is not a complete bottom-up saturation engine. Built-ins and proof search remain goal-directed; use `materialize/2` declarations and small output predicates when you want a specific relation, arity, or non-binary answer.
|
|
198
183
|
|
|
199
184
|
### Focusing default output
|
|
200
185
|
|
|
201
|
-
Large examples often have internal helper predicates. Add `materialize(Name, Arity).` declarations to restrict
|
|
186
|
+
Large examples often have internal helper predicates. Add `materialize(Name, Arity).` declarations to restrict default output to selected predicates:
|
|
202
187
|
|
|
203
188
|
```prolog
|
|
204
189
|
materialize(answer, 2).
|
|
@@ -214,7 +199,7 @@ The default output is then:
|
|
|
214
199
|
answer(case1, accepted).
|
|
215
200
|
```
|
|
216
201
|
|
|
217
|
-
`materialize/2` is a declaration, not a logical rule to prove. It
|
|
202
|
+
`materialize/2` is a declaration, not a logical rule to prove. It affects which predicates the CLI prints, not the meaning of the rules themselves.
|
|
218
203
|
|
|
219
204
|
## Writing programs
|
|
220
205
|
|
|
@@ -250,20 +235,14 @@ materialize(reason, 2).
|
|
|
250
235
|
|
|
251
236
|
Predicate names and atom constants use the same lexical form. Namespace-like names should be plain names such as `type`, `person_name`, or `odrl_permission`; colon names are not part of the language.
|
|
252
237
|
|
|
253
|
-
###
|
|
238
|
+
### Embedding remains general
|
|
254
239
|
|
|
255
|
-
The
|
|
256
|
-
|
|
257
|
-
```sh
|
|
258
|
-
bin/eyelang --query 'append(A, B, [a, b])' examples/list-collection.pl
|
|
259
|
-
bin/eyelang --query 'ackermann(4, 2, A)' examples/ackermann.pl
|
|
260
|
-
bin/eyelang --query 'once(solution(classic, S))' examples/sudoku.pl
|
|
261
|
-
```
|
|
240
|
+
The CLI is output-oriented and uses `materialize/2` to decide what to print. Embedders can still use the JavaScript API and `Solver` directly for arbitrary goals and arities.
|
|
262
241
|
|
|
263
242
|
Add `--stats` when you want lightweight solver counters on stderr without changing stdout:
|
|
264
243
|
|
|
265
244
|
```sh
|
|
266
|
-
bin/eyelang --stats
|
|
245
|
+
bin/eyelang --stats examples/sudoku.pl
|
|
267
246
|
```
|
|
268
247
|
|
|
269
248
|
The playground has matching `--stats` and `--proof` checkboxes, so browser runs can show the same counters or explanations like the CLI.
|
|
@@ -504,7 +483,7 @@ npm run test:regression
|
|
|
504
483
|
npm run test:examples
|
|
505
484
|
```
|
|
506
485
|
|
|
507
|
-
The conformance suite lives in [`conformance/`](conformance/) and is split into `core` and `extension` profiles matching `SPEC.md`. Each case is a small program with
|
|
486
|
+
The conformance suite lives in [`conformance/`](conformance/) and is split into `core` and `extension` profiles matching `SPEC.md`. Each case is a small program with an exact expected stdout file, and some internal conformance cases also include a goal file for testing the embeddable solver, so other implementations can reuse the same cases. The regression suite lives in [`test/run-regression.js`](test/run-regression.js) and covers CLI regressions, the public JavaScript API, and white-box invariants for parser, unification, and indexing behavior.
|
|
508
487
|
|
|
509
488
|
## Development and release
|
|
510
489
|
|
|
@@ -521,7 +500,7 @@ node bin/eyelang --help
|
|
|
521
500
|
Useful profiling smoke test:
|
|
522
501
|
|
|
523
502
|
```sh
|
|
524
|
-
bin/eyelang --stats
|
|
503
|
+
bin/eyelang --stats examples/sudoku.pl > /dev/null
|
|
525
504
|
```
|
|
526
505
|
|
|
527
506
|
For a release:
|
|
@@ -530,7 +509,7 @@ For a release:
|
|
|
530
509
|
2. update `README.md` and `SPEC.md`;
|
|
531
510
|
3. regenerate golden outputs if behavior changed;
|
|
532
511
|
4. run `npm test`;
|
|
533
|
-
5. publish the repository with `playground.html` and `playground-worker.mjs` if publishing the playground. The playground includes controls equivalent to CLI `--
|
|
512
|
+
5. publish the repository with `playground.html` and `playground-worker.mjs` if publishing the playground. The playground includes controls equivalent to CLI `--stats` and `--proof`.
|
|
534
513
|
|
|
535
514
|
## Performance notes
|
|
536
515
|
|
|
@@ -550,8 +529,8 @@ Ground facts use a fast path that avoids freshening and copying a rule body. Rec
|
|
|
550
529
|
memoize(path, 2).
|
|
551
530
|
```
|
|
552
531
|
|
|
553
|
-
For large programs, keep helper predicates selective, bind arguments early, and declare focused output predicates with `materialize/2` when default output would otherwise
|
|
532
|
+
For large programs, keep helper predicates selective, bind arguments early, and declare focused output predicates with `materialize/2` when default output would otherwise solve broad helper goals.
|
|
554
533
|
|
|
555
534
|
## Implementation limits
|
|
556
535
|
|
|
557
|
-
eyelang is intentionally smaller than ISO Prolog. It has no operators, cut, modules, dynamic database updates, DCGs, or complete ISO library. Negation is negation-as-failure through `not/1`. Search is goal-directed and expected to be finite for the
|
|
536
|
+
eyelang is intentionally smaller than ISO Prolog. It has no operators, cut, modules, dynamic database updates, DCGs, or complete ISO library. Negation is negation-as-failure through `not/1`. Search is goal-directed and expected to be finite for the selected output goals. Output explanations are non-normative proof printouts and do not change answer semantics.
|
package/SPEC.md
CHANGED
|
@@ -87,7 +87,7 @@ A **goal** is an atomic formula, a built-in call, or a comma conjunction.
|
|
|
87
87
|
|
|
88
88
|
A **source fact** is a fact written directly in the input program. A **new derivation** is a ground consequence found through at least one rule and not merely repeated from the source facts.
|
|
89
89
|
|
|
90
|
-
The **Herbrand universe** of a program is the set of all ground eyelang terms constructible from the constants and functors in the program, together with the built-in list constructors `[]` and `./2` where lists are used. The **Herbrand base** is the set of all ground atomic formulas whose predicate symbols occur in the program
|
|
90
|
+
The **Herbrand universe** of a program is the set of all ground eyelang terms constructible from the constants and functors in the program, together with the built-in list constructors `[]` and `./2` where lists are used. The **Herbrand base** is the set of all ground atomic formulas whose predicate symbols occur in the program and whose arguments are terms from the Herbrand universe.
|
|
91
91
|
|
|
92
92
|
## 2. Design goals
|
|
93
93
|
|
|
@@ -199,7 +199,7 @@ term ::= variable
|
|
|
199
199
|
list_items ::= term ("," term)* ["|" term]
|
|
200
200
|
```
|
|
201
201
|
|
|
202
|
-
Here `atom_constant` is a lexical class for symbolic scalar terms, not an atomic formula. Atomic formulas are represented by the grammar alternative `atom_constant "(" ... ")"` when such a compound appears in a clause head, rule body, or
|
|
202
|
+
Here `atom_constant` is a lexical class for symbolic scalar terms, not an atomic formula. Atomic formulas are represented by the grammar alternative `atom_constant "(" ... ")"` when such a compound appears in a clause head, rule body, or selected goal.
|
|
203
203
|
|
|
204
204
|
A clause head SHOULD be a compound term. Non-compound heads are parsed but are not useful in the current predicate index.
|
|
205
205
|
|
|
@@ -214,7 +214,7 @@ value(example, nil()).
|
|
|
214
214
|
|
|
215
215
|
### 5.1 Variables
|
|
216
216
|
|
|
217
|
-
Variables are scoped to a single clause or
|
|
217
|
+
Variables are scoped to a single clause or selected goal. A variable in a rule head and body denotes the same logical variable within that clause.
|
|
218
218
|
|
|
219
219
|
### 5.2 Atom constants, strings, and numbers
|
|
220
220
|
|
|
@@ -279,7 +279,7 @@ Clauses with the same predicate name and arity define one predicate group. Predi
|
|
|
279
279
|
|
|
280
280
|
Goals are solved left-to-right. For a user-defined atomic-formula goal, eyelang selects candidate clauses by predicate name, arity, and available indexes. A candidate clause is freshened, its head is unified with the goal, and then its body is solved.
|
|
281
281
|
|
|
282
|
-
A conjunction goal succeeds when all conjunct goals succeed in order.
|
|
282
|
+
A conjunction goal succeeds when all conjunct goals succeed in order. An answer is printed as the resolved answer term followed by a period.
|
|
283
283
|
|
|
284
284
|
### 7.1 Unification
|
|
285
285
|
|
|
@@ -291,7 +291,7 @@ A goal fails when no built-in case or user clause can prove it. eyelang has no e
|
|
|
291
291
|
|
|
292
292
|
### 7.3 Finite search expectation
|
|
293
293
|
|
|
294
|
-
Programs and
|
|
294
|
+
Programs and selected output goals SHOULD be written so the relevant search space is finite. eyelang includes recursion guards and memoization support, but it is not required to terminate for arbitrary recursive logic programs.
|
|
295
295
|
|
|
296
296
|
## 8. Logical reading: Herbrand semantics
|
|
297
297
|
|
|
@@ -317,7 +317,7 @@ Equivalently, the least Herbrand model is obtained by repeatedly applying the im
|
|
|
317
317
|
|
|
318
318
|
### 8.1 Variables and quantification
|
|
319
319
|
|
|
320
|
-
Variables do not range over external objects, records, pointers, or host-language values. In the logical reading, variables range over Herbrand terms. A rule is implicitly universally quantified over its variables. A
|
|
320
|
+
Variables do not range over external objects, records, pointers, or host-language values. In the logical reading, variables range over Herbrand terms. A rule is implicitly universally quantified over its variables. A selected goal is existential in the usual logic-programming sense: eyelang searches for substitutions of its variables by Herbrand terms that make the goal true with respect to the program.
|
|
321
321
|
|
|
322
322
|
### 8.2 Equality, identity, and unification
|
|
323
323
|
|
|
@@ -329,7 +329,7 @@ Operationally, eyelang uses first-order unification to find substitutions. The i
|
|
|
329
329
|
|
|
330
330
|
eyelang's CLI and library evaluator are goal-directed. They try to prove requested goals by resolving them against facts, rules, and built-ins, using clause order, goal order, indexing, memoization, and deterministic built-in execution. This operational strategy is intended to enumerate answers that are true in the least Herbrand model for the pure Horn-clause fragment, but it is not a complete bottom-up model enumerator. Non-terminating recursion or infinite generators can prevent an answer from being found even when the answer belongs to the least Herbrand model.
|
|
331
331
|
|
|
332
|
-
|
|
332
|
+
Default CLI output is also a host behavior, not a separate semantics. It asks broad materialization goals, suppresses duplicates, excludes source facts, keeps ground answers, and prints selected consequences. Embedders can still access the goal-directed solver directly through the implementation API.
|
|
333
333
|
|
|
334
334
|
### 8.4 Built-ins and operational extensions
|
|
335
335
|
|
|
@@ -498,7 +498,7 @@ memoize(path, 2).
|
|
|
498
498
|
materialize(Name, Arity).
|
|
499
499
|
```
|
|
500
500
|
|
|
501
|
-
`Name` MUST be an atom constant and `Arity` MUST be a non-negative integer. If a program contains one or more `materialize/2` declarations,
|
|
501
|
+
`Name` MUST be an atom constant and `Arity` MUST be a non-negative integer. If a program contains one or more `materialize/2` declarations, default CLI output is restricted to those predicate groups. Source facts are still excluded from printed output.
|
|
502
502
|
|
|
503
503
|
Example:
|
|
504
504
|
|
|
@@ -507,7 +507,7 @@ materialize(status, 2).
|
|
|
507
507
|
materialize(reason, 2).
|
|
508
508
|
```
|
|
509
509
|
|
|
510
|
-
`materialize/2` does not
|
|
510
|
+
`materialize/2` affects host output selection only; it does not change the logical meaning of the program.
|
|
511
511
|
|
|
512
512
|
## 12. eyelang Sockets
|
|
513
513
|
|
|
@@ -515,7 +515,7 @@ A **eyelang Socket** is a declared semantic opening in a eyelang program where f
|
|
|
515
515
|
|
|
516
516
|
The term follows the ordinary socket pattern: a socket defines a place where a matching provider can connect. In eyelang, the matching part is knowledge. A socket identifies what shape of knowledge a program expects; a plug identifies which provider supplies it. This separates reasoning logic from knowledge providers and makes composition boundaries visible as eyelang data.
|
|
517
517
|
|
|
518
|
-
In this specification, sockets are a portable **programming pattern** expressed with ordinary facts. The core solver does not give `socket/2`, `plug/2`, `provides/1`, or `requires/1` special proof-search behavior unless a host explicitly documents such an extension. Because they are ordinary facts, socket declarations remain readable,
|
|
518
|
+
In this specification, sockets are a portable **programming pattern** expressed with ordinary facts. The core solver does not give `socket/2`, `plug/2`, `provides/1`, or `requires/1` special proof-search behavior unless a host explicitly documents such an extension. Because they are ordinary facts, socket declarations remain readable, inspectable, explainable, and safe to ignore by hosts that do not validate them.
|
|
519
519
|
|
|
520
520
|
### 12.1 Socket vocabulary
|
|
521
521
|
|
|
@@ -566,7 +566,7 @@ ancestor(X, Z) :-
|
|
|
566
566
|
|
|
567
567
|
The `ancestor/2` rules do not depend on a particular storage mechanism for `parent/2`. In a small test, the provider may be the same file. In an embedded host, it may be a database adapter, a document extractor, a remote service, or another eyelang module. The socket facts make that boundary explicit without changing the logical meaning of the rules.
|
|
568
568
|
|
|
569
|
-
When eyelang derives `ancestor(pat, emma)`, the answer explanation can still refer to the source clauses that were actually used, for example facts for `parent/2` and rules for `ancestor/2`. The socket facts add
|
|
569
|
+
When eyelang derives `ancestor(pat, emma)`, the answer explanation can still refer to the source clauses that were actually used, for example facts for `parent/2` and rules for `ancestor/2`. The socket facts add an inspectable description of where such knowledge is intended to enter.
|
|
570
570
|
|
|
571
571
|
### 12.3 Sockets and AI agents
|
|
572
572
|
|
|
@@ -578,13 +578,13 @@ This gives a clear division of labor: AI can help generate, translate, and conne
|
|
|
578
578
|
|
|
579
579
|
Normal answer output prints one resolved answer term followed by a period. Strings are double-quoted; atom constants are quoted when needed; lists use list syntax; compound terms use functor notation. Host interfaces MAY provide an option such as `--proof` to add `why/2` explanation facts; this option MUST NOT change the answers found.
|
|
580
580
|
|
|
581
|
-
Output SHOULD be accepted as eyelang input when it contains only supported term syntax. Explanations are ordinary eyelang facts, so answer output can be read back and
|
|
581
|
+
Output SHOULD be accepted as eyelang input when it contains only supported term syntax. Explanations are ordinary eyelang facts, so answer output can be read back and processed by eyelang.
|
|
582
582
|
|
|
583
|
-
|
|
583
|
+
Default host output behavior is:
|
|
584
584
|
|
|
585
585
|
1. parse all inputs into one program;
|
|
586
586
|
2. collect source fact lines for duplicate suppression;
|
|
587
|
-
3. if `materialize/2` declarations exist,
|
|
587
|
+
3. if `materialize/2` declarations exist, solve those predicate groups; otherwise solve all binary predicate groups with at least one rule;
|
|
588
588
|
4. keep only ground answers;
|
|
589
589
|
5. remove answers identical to source facts;
|
|
590
590
|
6. suppress duplicates;
|
|
@@ -617,7 +617,7 @@ A conforming standard host also supports:
|
|
|
617
617
|
|
|
618
618
|
- `memoize/2` declarations;
|
|
619
619
|
- `materialize/2` declarations;
|
|
620
|
-
- default
|
|
620
|
+
- default derived output;
|
|
621
621
|
- explanation output;
|
|
622
622
|
- stdin, file, and URL inputs in the CLI.
|
|
623
623
|
|
|
@@ -679,4 +679,4 @@ status(a, open) :- open(a).
|
|
|
679
679
|
|
|
680
680
|
URL input uses host networking support when available. Hosts SHOULD treat downloaded programs as untrusted code because they can trigger expensive search.
|
|
681
681
|
|
|
682
|
-
Programs SHOULD be written with finite search in mind. Broad
|
|
682
|
+
Programs SHOULD be written with finite search in mind. Broad default materialization can be expensive for helper predicates; use `materialize/2` declarations and concise output predicates when needed.
|
package/bin/eyelang
CHANGED
|
File without changes
|
package/conformance/README.md
CHANGED
|
@@ -5,7 +5,6 @@ This directory contains the executable conformance cases for the eyelang languag
|
|
|
5
5
|
The suite is intentionally file-based so another implementation can run the same programs and compare exact standard output. A case consists of:
|
|
6
6
|
|
|
7
7
|
- `conformance/cases/<profile>/<name>.pl` — input program;
|
|
8
|
-
- optional `conformance/cases/<profile>/<name>.query` — query text passed to `eyelang --query`;
|
|
9
8
|
- `conformance/expected/<profile>/<name>.out` — exact expected standard output.
|
|
10
9
|
|
|
11
10
|
The current runner compares standard output, including answer facts and their `why/2` explanation facts. Standard error, performance, and resource limits are outside this suite.
|
|
@@ -31,16 +30,16 @@ node test/run-conformance.js core
|
|
|
31
30
|
node test/run-conformance.js extension
|
|
32
31
|
```
|
|
33
32
|
|
|
34
|
-
The runner executes
|
|
33
|
+
The runner executes materialized programs in-process through the public JavaScript API so small conformance cases avoid measuring Node startup overhead.
|
|
35
34
|
|
|
36
35
|
## Profiles
|
|
37
36
|
|
|
38
|
-
`core` covers the portable core language profile from `../SPEC.md`: lexical syntax, facts, definite clauses, first-order terms, lists, conjunction, unification through user predicates, left-to-right goal-directed proof search, and answer printing
|
|
37
|
+
`core` covers the portable core language profile from `../SPEC.md`: lexical syntax, facts, definite clauses, first-order terms, lists, conjunction, unification through user predicates, left-to-right goal-directed proof search, and answer printing.
|
|
39
38
|
|
|
40
|
-
`extension` covers the standard built-in and host behavior exercised by the current reference implementation: arithmetic, comparison, strings, list relations, aggregation, formula-term helpers, `memoize/2`, `materialize/2`, and default
|
|
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, `memoize/2`, `materialize/2`, and default derived output.
|
|
41
40
|
|
|
42
41
|
The profile name `extension` is a test-suite grouping name. It does not mean that these cases are outside the eyelang specification; most of them correspond to the standard built-in profile and standard host profile in `../SPEC.md`.
|
|
43
42
|
|
|
44
43
|
## Updating expected output
|
|
45
44
|
|
|
46
|
-
There is no committed auto-accept mode. To update an expected file, run the matching case with
|
|
45
|
+
There is no committed auto-accept mode. To update an expected file, run the matching case with the conformance runner, inspect the result, and replace the corresponding file under `conformance/expected/<profile>/` deliberately.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
% SPEC 6, 7: definite clauses, conjunction, and recursive proof search.
|
|
2
|
+
materialize(ancestor, 2).
|
|
2
3
|
parent(pat, jan).
|
|
3
4
|
parent(jan, emma).
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
ancestor_any(X, Y) :- parent(X, Y).
|
|
6
|
+
ancestor_any(X, Z) :- parent(X, Y), ancestor_any(Y, Z).
|
|
7
|
+
ancestor(pat, Y) :- ancestor_any(pat, Y).
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
% SPEC 3, 5, 11: scalars, compounds, lists, and read-back printing.
|
|
2
|
-
value
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
2
|
+
materialize(value, 2).
|
|
3
|
+
raw_value(atom, pat).
|
|
4
|
+
raw_value(quoted_atom, 'atom with spaces').
|
|
5
|
+
raw_value(quoted_quote, 'needs''quote').
|
|
6
|
+
raw_value(empty_atom, '').
|
|
7
|
+
raw_value(string, "line\nquote: \"ok\"").
|
|
8
|
+
raw_value(integer, -42).
|
|
9
|
+
raw_value(decimal, 0.25).
|
|
10
|
+
raw_value(scientific, 1.25e-3).
|
|
11
|
+
raw_value(compound, pair(3, nested(atom, [x, y]))).
|
|
12
|
+
raw_value(zero_arity, nil()).
|
|
13
|
+
raw_value(empty_list, []).
|
|
14
|
+
raw_value(proper_list, [a, b, c]).
|
|
15
|
+
raw_value(improper_list, [a, b | tail]).
|
|
16
|
+
value(K, V) :- raw_value(K, V).
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
% SPEC 10.1: memoize/2 is a declaration and does not change answers.
|
|
2
|
-
|
|
2
|
+
materialize(reach, 2).
|
|
3
|
+
memoize(reach_any, 2).
|
|
3
4
|
edge(a, b).
|
|
4
5
|
edge(b, c).
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
reach_any(X, Y) :- edge(X, Y).
|
|
7
|
+
reach_any(X, Z) :- edge(X, Y), reach_any(Y, Z).
|
|
8
|
+
reach(a, Y) :- reach_any(a, Y).
|