eyeling 1.16.5 → 1.17.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/HANDBOOK.md CHANGED
@@ -1537,7 +1537,7 @@ Implementation: this is implemented by `lib/trace.js` and called from `lib/engin
1537
1537
 
1538
1538
  As a goal, this builtin simply checks that the terms are sufficiently bound/usable and then succeeds. The actual “printing” behavior is handled by the CLI:
1539
1539
 
1540
- - When you run Eyeling with `--strings` / `-r`, the CLI collects all `log:outputString` triples from the _saturated_ closure.
1540
+ - When the final closure contains any `log:outputString` triples, the CLI collects all of them from the _saturated_ closure and renders those strings instead of the default N3 output.
1541
1541
  - It sorts them deterministically by the subject “key” and concatenates the string values in that order.
1542
1542
 
1543
1543
  This is a pure test/side-effect marker (it shouldn’t drive search; it should merely validate that strings exist once other reasoning has produced them). In forward rules Eyeling may defer it if it is reached before the terms are usable.
@@ -1656,7 +1656,7 @@ Matches the regex once and returns the **first capturing group** (group 1). If t
1656
1656
 
1657
1657
  From a logic-programming point of view, printing is awkward: if you print _during_ proof search, you risk producing output along branches that later backtrack, or producing the same line multiple times in different derivations. Eyeling avoids that whole class of problems by treating “output” as **data**.
1658
1658
 
1659
- The predicate `log:outputString` is the only officially supported “side-effect channel”, and even it is handled in two phases:
1659
+ The predicate `log:outputString` is the only officially supported “side-effect channel”, and even it is handled in two phases. If any final `log:outputString` facts exist, Eyeling renders them automatically as the CLI output:
1660
1660
 
1661
1661
  1. **During reasoning (declarative phase):**
1662
1662
  `log:outputString` behaves like a pure test builtin (implemented in `lib/builtins.js`): it succeeds when its arguments are well-formed and sufficiently bound (notably, when the object is a string literal that can be emitted). Importantly, it does _not_ print anything at this time. If a rule derives a triple like:
@@ -1675,7 +1675,7 @@ This separation is not just an aesthetic choice; it preserves the meaning of log
1675
1675
  - Output becomes explainable. If you enable proof comments or inspect the closure, `log:outputString` facts can be traced back to the rules that produced them.
1676
1676
  - Output becomes compositional. You can reason about output strings (e.g., sort them, filter them, derive them conditionally) just like any other data.
1677
1677
 
1678
- In short: Eyeling makes `log:outputString` safe by refusing to treat it as an immediate effect. It is a _declarative output fact_ whose concrete rendering is a final, deterministic post-processing step.
1678
+ In short: Eyeling makes `log:outputString` safe by refusing to treat it as an immediate effect. It is a _declarative output fact_ whose concrete rendering is a final, deterministic post-processing step. If any such facts are present in the final closure, Eyeling renders those strings automatically instead of printing the default N3 result set.
1679
1679
 
1680
1680
  ---
1681
1681
 
@@ -1773,7 +1773,7 @@ The bundle contains the whole engine. The CLI path is the “canonical behavior
1773
1773
 
1774
1774
  - parse input file
1775
1775
  - reason to closure
1776
- - print derived triples or output strings
1776
+ - print derived triples, or render `log:outputString` strings when present
1777
1777
  - optional proof comments
1778
1778
  - optional streaming
1779
1779
 
@@ -1785,7 +1785,6 @@ The current CLI supports a small set of flags (see `lib/cli.js`):
1785
1785
  - `-d`, `--deterministic-skolem` — make `log:skolem` stable across runs.
1786
1786
  - `-e`, `--enforce-https` — rewrite `http://…` to `https://…` for dereferencing builtins.
1787
1787
  - `-p`, `--proof-comments` — include per-fact proof comment blocks in output.
1788
- - `-r`, `--strings` — after reasoning, render only `log:outputString` values (ordered by subject key).
1789
1788
  - `-s`, `--super-restricted` — disable all builtins except `log:implies` / `log:impliedBy`.
1790
1789
  - `-t`, `--stream` — stream derived triples as soon as they are derived.
1791
1790
  - `-v`, `--version` — print version and exit.
@@ -1988,13 +1987,12 @@ Options:
1988
1987
  -e, --enforce-https Rewrite http:// IRIs to https:// for log dereferencing builtins.
1989
1988
  -h, --help Show this help and exit.
1990
1989
  -p, --proof-comments Enable proof explanations.
1991
- -r, --strings Print log:outputString strings (ordered by key) instead of N3 output.
1992
1990
  -s, --super-restricted Disable all builtins except => and <=.
1993
1991
  -t, --stream Stream derived triples as soon as they are derived.
1994
1992
  -v, --version Print version and exit.
1995
1993
  ```
1996
1994
 
1997
- Note: when `log:query` directives are present, Eyeling cannot stream output (the selected results depend on the saturated closure), so `--stream` has no effect in that mode.
1995
+ Note: when `log:query` directives are present, or when the program may produce `log:outputString` facts, Eyeling cannot stream its final user-facing output from partial derivations, so `--stream` has no effect in those cases. In the latter case Eyeling saturates first and then renders the collected output strings.
1998
1996
 
1999
1997
  See also:
2000
1998
 
@@ -2653,7 +2651,7 @@ For many real workflows, that combination is more useful than a bare result: it
2653
2651
 
2654
2652
  Eyeling already encourages the separation that ARC needs.
2655
2653
 
2656
- Rules derive facts. Facts can include output facts. Output is not printed eagerly during proof search; instead, `log:outputString` facts are collected from the final closure and rendered deterministically, for example with `-r` / `--strings`. This makes it natural to derive a structured Answer and Reason Why as part of the logic itself.
2654
+ Rules derive facts. Facts can include output facts. Output is not printed eagerly during proof search; instead, `log:outputString` facts are collected from the final closure and rendered deterministically whenever they are present. This makes it natural to derive a structured Answer and Reason Why as part of the logic itself.
2657
2655
 
2658
2656
  Checks also map well to Eyeling. A rule with conclusion `false` acts as an inference fuse: if its body becomes provable, execution stops with a hard failure. This is exactly the behavior we want for “must-hold” conditions.
2659
2657
 
package/README.md CHANGED
@@ -44,7 +44,7 @@ Show all options:
44
44
  npx eyeling --help
45
45
  ```
46
46
 
47
- Useful flags include `--proof-comments`, `--stream`, `--strings`, and `--enforce-https`.
47
+ Useful flags include `--proof-comments`, `--stream`, and `--enforce-https`. If the final closure contains any `log:outputString` triples, Eyeling now renders those strings automatically instead of printing N3 output.
48
48
 
49
49
  ## What gets printed?
50
50
 
@@ -1,22 +1,21 @@
1
- # ===========================================================================
2
- # Control System — ARC-style rewrite of Eyeling's control example.
3
- # Original example: https://raw.githubusercontent.com/eyereasoner/eyeling/refs/heads/main/examples/control-system.n3
1
+ # =============================================================================
2
+ # Control System — ARC-style
4
3
  #
5
4
  # This example shows how a small control system turns sensor readings into two
6
5
  # actuator commands. One command anticipates a known disturbance before it hits
7
6
  # the system. The other compares the measured output with the target and then
8
7
  # corrects the remaining gap. The ARC presentation makes the result easy to
9
8
  # inspect by giving an Answer, a clear Reason Why, and independent Checks.
10
- # ===========================================================================
9
+ # =============================================================================
11
10
 
12
11
  @prefix log: <http://www.w3.org/2000/10/swap/log#>.
13
12
  @prefix math: <http://www.w3.org/2000/10/swap/math#>.
14
13
  @prefix string: <http://www.w3.org/2000/10/swap/string#>.
15
14
  @prefix : <https://example.org/control-system#>.
16
15
 
17
- # ---------------------------------------------------------------------------
16
+ # -----
18
17
  # Facts
19
- # ---------------------------------------------------------------------------
18
+ # -----
20
19
 
21
20
  # input
22
21
  :input1 :measurement1 (6 11).
@@ -36,9 +35,9 @@
36
35
  :output2 :measurement4 24.
37
36
  :output2 :target2 29.
38
37
 
39
- # ---------------------------------------------------------------------------
40
- # Original control logic, preserved from the source example
41
- # ---------------------------------------------------------------------------
38
+ # -------------
39
+ # control logic
40
+ # -------------
42
41
 
43
42
  { :input1 :measurement10 ?M1.
44
43
  :input2 :measurement2 true.
@@ -78,9 +77,9 @@
78
77
  ?M1 math:notLessThan ?M2.
79
78
  }.
80
79
 
81
- # ---------------------------------------------------------------------------
80
+ # -------------------------------------------------------------------
82
81
  # Explanation layer: compute an explicit why-story from the raw facts
83
- # ---------------------------------------------------------------------------
82
+ # -------------------------------------------------------------------
84
83
 
85
84
  { :input1 :measurement1 (?Low ?High).
86
85
  ?Low math:lessThan ?High.
@@ -134,9 +133,9 @@
134
133
  :actuator1Command ?A1;
135
134
  :actuator2Command ?A2. }.
136
135
 
137
- # ---------------------------------------------------------------------------
136
+ # ----------
138
137
  # ARC report
139
- # ---------------------------------------------------------------------------
138
+ # ----------
140
139
 
141
140
  { :decision :answer ?Answer;
142
141
  :actuator1Command ?A1;
@@ -1,78 +1,208 @@
1
- # =====================================================================
2
- # Easter Date
3
- # Calculation of easter dates.
4
- # original copy at http://www.w3.org/2000/10/swap/test/easter/easter.n3
5
- # =====================================================================
6
-
7
- @prefix math: <http://www.w3.org/2000/10/swap/math#>.
8
- @prefix log: <http://www.w3.org/2000/10/swap/log#>.
9
- @prefix string: <http://www.w3.org/2000/10/swap/string#>.
10
- @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
11
- @prefix xsd: <http://www.w3.org/2001/XMLSchema#>.
12
- @prefix prolog: <http://eulersharp.sourceforge.net/2003/03swap/prolog#>.
13
- @prefix : <http://www.agfa.com/w3c/euler/easterP#>.
14
-
15
- <> rdfs:comment """
16
- Divide by Quotient Remainder
17
- ---------------------------------------------------
18
- y 19 j
19
- y 100 k h
20
- k 4 m n
21
- k + 8 25 p
22
- k - p + 1 3 q
23
- 19j + k - m - q + 15 30 r
24
- h 4 s u
25
- 32 + 2n + 2s - r - u 7 v
26
- j + 11r + 22v 451 w
27
- r + v - 7w + 114 31 x z
28
-
29
- Here x is the number of the month ond 1 + z is the day of that
30
- month upon which Easter Sunday falls in the year y.
31
- """.
32
-
33
- 2021 a :Year.
34
- 2022 a :Year.
35
- 2023 a :Year.
36
- 2024 a :Year.
37
- 2025 a :Year.
38
- 2026 a :Year.
39
- 2027 a :Year.
40
- 2028 a :Year.
41
- 2029 a :Year.
42
- 2030 a :Year.
43
- 2031 a :Year.
44
- 2032 a :Year.
45
- 2033 a :Year.
46
- 2034 a :Year.
47
- 2035 a :Year.
48
- 2036 a :Year.
49
- 2037 a :Year.
50
- 2038 a :Year.
51
- 2039 a :Year.
52
- 2040 a :Year.
53
- 2041 a :Year.
54
- 2042 a :Year.
55
- 2043 a :Year.
56
- 2044 a :Year.
57
- 2045 a :Year.
58
- 2046 a :Year.
59
- 2047 a :Year.
60
- 2048 a :Year.
61
- 2049 a :Year.
62
- 2050 a :Year.
63
-
64
- { ?Y a :Year.
65
- (?Y 19) math:remainder ?J.
66
- (?Y 100) math:integerQuotient ?K; math:remainder ?H.
67
- (?K 4) math:integerQuotient ?M; math:remainder ?N.
68
- ((?K 8)!math:sum 25) math:integerQuotient ?P.
69
- (((?K ?P)!math:difference 1)!math:sum 3) math:integerQuotient ?Q.
70
- ((((((19 ?J)!math:product ?K)!math:sum ?M)!math:difference ?Q)!math:difference 15)!math:sum 30) math:remainder ?R.
71
- (?H 4) math:integerQuotient ?S; math:remainder ?U.
72
- ((32 (2 ?N)!math:product (2 ?S)!math:product ?R!math:negation ?U!math:negation)!math:sum 7) math:remainder ?V.
73
- ((?J (11 ?R)!math:product (22 ?V)!math:product)!math:sum 451) math:integerQuotient ?W.
74
- ((?R ?V (7 ?W)!math:product!math:negation 114)!math:sum 31) math:integerQuotient ?X; math:remainder ?Z.
75
- (?Z 1) math:sum ?DAY.
76
- } => {
77
- (?DAY ?X) :easterFor ?Y.
78
- }.
1
+ # ==========================================================================
2
+ # Easter — ARC-style
3
+ #
4
+ # This example computes the date of Easter Sunday in the Gregorian calendar.
5
+ # For each year in a sample range, it applies the classic computus step by
6
+ # step, explains the resulting month and day, and then checks independent
7
+ # properties of the result: cycle bounds, remainder bounds, and the legal
8
+ # Easter date window in March or April.
9
+ # ==========================================================================
10
+
11
+ @prefix : <https://example.org/easter-arc#> .
12
+ @prefix math: <http://www.w3.org/2000/10/swap/math#> .
13
+ @prefix log: <http://www.w3.org/2000/10/swap/log#> .
14
+ @prefix string: <http://www.w3.org/2000/10/swap/string#> .
15
+ @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
16
+ @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
17
+
18
+ <> rdfs:comment """This ARC-style version keeps the Gregorian computus from the original example and reports, for each sample year, an Answer, a Reason Why, and a set of independent Checks.""" .
19
+
20
+ :y2026 a :Case; :year 2026 .
21
+ :y2027 a :Case; :year 2027 .
22
+ :y2028 a :Case; :year 2028 .
23
+ :y2029 a :Case; :year 2029 .
24
+ :y2030 a :Case; :year 2030 .
25
+ :y2031 a :Case; :year 2031 .
26
+ :y2032 a :Case; :year 2032 .
27
+ :y2033 a :Case; :year 2033 .
28
+ :y2034 a :Case; :year 2034 .
29
+ :y2035 a :Case; :year 2035 .
30
+
31
+ :goldenRemainder :value 0 .
32
+ :goldenRemainder :value 1 .
33
+ :goldenRemainder :value 2 .
34
+ :goldenRemainder :value 3 .
35
+ :goldenRemainder :value 4 .
36
+ :goldenRemainder :value 5 .
37
+ :goldenRemainder :value 6 .
38
+ :goldenRemainder :value 7 .
39
+ :goldenRemainder :value 8 .
40
+ :goldenRemainder :value 9 .
41
+ :goldenRemainder :value 10 .
42
+ :goldenRemainder :value 11 .
43
+ :goldenRemainder :value 12 .
44
+ :goldenRemainder :value 13 .
45
+ :goldenRemainder :value 14 .
46
+ :goldenRemainder :value 15 .
47
+ :goldenRemainder :value 16 .
48
+ :goldenRemainder :value 17 .
49
+ :goldenRemainder :value 18 .
50
+
51
+ :epactRemainder :value 0 .
52
+ :epactRemainder :value 1 .
53
+ :epactRemainder :value 2 .
54
+ :epactRemainder :value 3 .
55
+ :epactRemainder :value 4 .
56
+ :epactRemainder :value 5 .
57
+ :epactRemainder :value 6 .
58
+ :epactRemainder :value 7 .
59
+ :epactRemainder :value 8 .
60
+ :epactRemainder :value 9 .
61
+ :epactRemainder :value 10 .
62
+ :epactRemainder :value 11 .
63
+ :epactRemainder :value 12 .
64
+ :epactRemainder :value 13 .
65
+ :epactRemainder :value 14 .
66
+ :epactRemainder :value 15 .
67
+ :epactRemainder :value 16 .
68
+ :epactRemainder :value 17 .
69
+ :epactRemainder :value 18 .
70
+ :epactRemainder :value 19 .
71
+ :epactRemainder :value 20 .
72
+ :epactRemainder :value 21 .
73
+ :epactRemainder :value 22 .
74
+ :epactRemainder :value 23 .
75
+ :epactRemainder :value 24 .
76
+ :epactRemainder :value 25 .
77
+ :epactRemainder :value 26 .
78
+ :epactRemainder :value 27 .
79
+ :epactRemainder :value 28 .
80
+ :epactRemainder :value 29 .
81
+
82
+ :weekdayRemainder :value 0 .
83
+ :weekdayRemainder :value 1 .
84
+ :weekdayRemainder :value 2 .
85
+ :weekdayRemainder :value 3 .
86
+ :weekdayRemainder :value 4 .
87
+ :weekdayRemainder :value 5 .
88
+ :weekdayRemainder :value 6 .
89
+
90
+ :slot_m3_d22 :monthNum 3; :day 22 .
91
+ :slot_m3_d23 :monthNum 3; :day 23 .
92
+ :slot_m3_d24 :monthNum 3; :day 24 .
93
+ :slot_m3_d25 :monthNum 3; :day 25 .
94
+ :slot_m3_d26 :monthNum 3; :day 26 .
95
+ :slot_m3_d27 :monthNum 3; :day 27 .
96
+ :slot_m3_d28 :monthNum 3; :day 28 .
97
+ :slot_m3_d29 :monthNum 3; :day 29 .
98
+ :slot_m3_d30 :monthNum 3; :day 30 .
99
+ :slot_m3_d31 :monthNum 3; :day 31 .
100
+ :slot_m4_d1 :monthNum 4; :day 1 .
101
+ :slot_m4_d2 :monthNum 4; :day 2 .
102
+ :slot_m4_d3 :monthNum 4; :day 3 .
103
+ :slot_m4_d4 :monthNum 4; :day 4 .
104
+ :slot_m4_d5 :monthNum 4; :day 5 .
105
+ :slot_m4_d6 :monthNum 4; :day 6 .
106
+ :slot_m4_d7 :monthNum 4; :day 7 .
107
+ :slot_m4_d8 :monthNum 4; :day 8 .
108
+ :slot_m4_d9 :monthNum 4; :day 9 .
109
+ :slot_m4_d10 :monthNum 4; :day 10 .
110
+ :slot_m4_d11 :monthNum 4; :day 11 .
111
+ :slot_m4_d12 :monthNum 4; :day 12 .
112
+ :slot_m4_d13 :monthNum 4; :day 13 .
113
+ :slot_m4_d14 :monthNum 4; :day 14 .
114
+ :slot_m4_d15 :monthNum 4; :day 15 .
115
+ :slot_m4_d16 :monthNum 4; :day 16 .
116
+ :slot_m4_d17 :monthNum 4; :day 17 .
117
+ :slot_m4_d18 :monthNum 4; :day 18 .
118
+ :slot_m4_d19 :monthNum 4; :day 19 .
119
+ :slot_m4_d20 :monthNum 4; :day 20 .
120
+ :slot_m4_d21 :monthNum 4; :day 21 .
121
+ :slot_m4_d22 :monthNum 4; :day 22 .
122
+ :slot_m4_d23 :monthNum 4; :day 23 .
123
+ :slot_m4_d24 :monthNum 4; :day 24 .
124
+ :slot_m4_d25 :monthNum 4; :day 25 .
125
+
126
+ # --------
127
+ # Computus
128
+ # --------
129
+
130
+ { ?Case a :Case; :year ?Y.
131
+ (?Y 19) math:remainder ?J.
132
+ (?Y 100) math:integerQuotient ?K; math:remainder ?H.
133
+ (?K 4) math:integerQuotient ?M; math:remainder ?N.
134
+ ((?K 8)!math:sum 25) math:integerQuotient ?P.
135
+ (((?K ?P)!math:difference 1)!math:sum 3) math:integerQuotient ?Q.
136
+ ((((((19 ?J)!math:product ?K)!math:sum ?M)!math:difference ?Q)!math:difference 15)!math:sum 30)
137
+ math:remainder ?R.
138
+ (?H 4) math:integerQuotient ?S; math:remainder ?U.
139
+ ((32 (2 ?N)!math:product (2 ?S)!math:product ?R!math:negation ?U!math:negation)!math:sum 7)
140
+ math:remainder ?V.
141
+ ((?J (11 ?R)!math:product (22 ?V)!math:product)!math:sum 451)
142
+ math:integerQuotient ?W.
143
+ ((?R ?V (7 ?W)!math:product!math:negation 114)!math:sum 31)
144
+ math:integerQuotient ?X; math:remainder ?Z.
145
+ (?Z 1) math:sum ?DAY.
146
+ }
147
+ =>
148
+ { ?Case
149
+ :j ?J;
150
+ :k ?K;
151
+ :h ?H;
152
+ :m ?M;
153
+ :n ?N;
154
+ :p ?P;
155
+ :q ?Q;
156
+ :r ?R;
157
+ :s ?S;
158
+ :u ?U;
159
+ :v ?V;
160
+ :w ?W;
161
+ :monthNum ?X;
162
+ :day ?DAY;
163
+ :z ?Z. } .
164
+
165
+ { ?Case :monthNum 3. } => { ?Case :monthName "March". } .
166
+ { ?Case :monthNum 4. } => { ?Case :monthName "April". } .
167
+
168
+ # ------------------
169
+ # Independent checks
170
+ # ------------------
171
+
172
+ { ?Case :j ?J. :goldenRemainder :value ?J. }
173
+ => { ?Case :check1 "C1 OK - the Golden Number remainder j is inside the 0–18 cycle.\n" . } .
174
+
175
+ { ?Case :r ?R. :epactRemainder :value ?R. }
176
+ => { ?Case :check2 "C2 OK - the epact-style remainder r is inside the 0–29 cycle.\n" . } .
177
+
178
+ { ?Case :v ?V. :weekdayRemainder :value ?V. }
179
+ => { ?Case :check3 "C3 OK - the weekday adjustment v is inside the 0–6 cycle.\n" . } .
180
+
181
+ { ?Case :monthNum ?M; :monthName ?Name. }
182
+ => { ?Case :check4 "C4 OK - the final month is a valid Easter month (March or April).\n" . } .
183
+
184
+ { ?Case :monthNum ?M; :day ?D.
185
+ ?Slot :monthNum ?M; :day ?D. }
186
+ => { ?Case :check5 "C5 OK - the final date is inside the legal Gregorian Easter window.\n" . } .
187
+
188
+ # ----------------
189
+ # ARC-style report
190
+ # ----------------
191
+
192
+ { ?Case :year ?Y; :monthName ?Month; :day ?Day;
193
+ :j ?J; :k ?K; :q ?Q; :r ?R; :v ?V; :monthNum ?X; :z ?Z;
194
+ :check1 ?C1; :check2 ?C2; :check3 ?C3; :check4 ?C4; :check5 ?C5.
195
+ (
196
+ "Easter — Gregorian computus\n\n"
197
+ "=== " ?Y " ===\n"
198
+ "Answer\n"
199
+ "Easter Sunday falls on " ?Month " " ?Day ".\n\n"
200
+ "Reason Why\n"
201
+ "For year " ?Y ", the computus gives j=" ?J ", k=" ?K ", q=" ?Q
202
+ ", r=" ?R ", v=" ?V ", and final month/day numbers x=" ?X ", z=" ?Z ". "
203
+ "Because the day is z+1, the resulting Easter date is " ?Month " " ?Day ".\n\n"
204
+ "Check\n"
205
+ ?C1 ?C2 ?C3 ?C4 ?C5
206
+ ) string:concatenation ?Block. }
207
+ =>
208
+ { :report log:outputString ?Block. } .