eyelang 1.7.9 → 1.7.11

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 (53) hide show
  1. package/docs/guide.md +11 -3
  2. package/docs/language-reference.md +4 -4
  3. package/examples/animal.eye +1 -1
  4. package/examples/dairy-energy-balance.eye +3 -3
  5. package/examples/dijkstra-risk-path.eye +1 -1
  6. package/examples/ev-range-worlds.eye +10 -10
  7. package/examples/fft8-numeric.eye +1 -1
  8. package/examples/field-nitrogen-balance.eye +7 -7
  9. package/examples/fundamental-theorem-arithmetic.eye +2 -2
  10. package/examples/gps.eye +8 -8
  11. package/examples/illegitimate-reasoning.eye +7 -7
  12. package/examples/map-four-color-search.eye +65 -0
  13. package/examples/matrix-noncommutativity.eye +43 -0
  14. package/examples/monkey-bananas.eye +4 -4
  15. package/examples/output/map-four-color-search.eye +1 -0
  16. package/examples/output/matrix-noncommutativity.eye +3 -0
  17. package/examples/output/peano-calculus.eye +3 -0
  18. package/examples/output/prime-range.eye +3 -0
  19. package/examples/output/route-planning.eye +4 -0
  20. package/examples/output/shoelace-polygon-area.eye +1 -0
  21. package/examples/output/symbolic-derivative.eye +4 -0
  22. package/examples/output/workplace-compliance.eye +4 -0
  23. package/examples/peano-calculus.eye +40 -0
  24. package/examples/prime-range.eye +45 -0
  25. package/examples/route-planning.eye +33 -0
  26. package/examples/shoelace-polygon-area.eye +22 -0
  27. package/examples/symbolic-derivative.eye +39 -0
  28. package/examples/wolf-goat-cabbage.eye +2 -2
  29. package/examples/workplace-compliance.eye +41 -0
  30. package/examples/zebra.eye +21 -21
  31. package/package.json +1 -1
  32. package/playground.html +15 -4
  33. package/src/parser.js +8 -8
  34. package/src/term.js +1 -1
  35. package/test/conformance/cases/arithmetic/extra_division_by_zero_fails.eye +1 -1
  36. package/test/conformance/cases/atoms/103_angle_iri_atoms.eye +2 -2
  37. package/test/conformance/cases/builtins/extra_difference_end_before_start_fails.eye +1 -1
  38. package/test/conformance/cases/builtins/extra_difference_invalid_date_fails.eye +1 -1
  39. package/test/conformance/cases/context/extra_holds_ignores_string_parts.eye +1 -1
  40. package/test/conformance/cases/lists/020_nested_list_terms.eye +1 -1
  41. package/test/conformance/cases/lists/extra_length_improper_fails.eye +1 -1
  42. package/test/conformance/cases/rules/022_rule_head_structure.eye +2 -2
  43. package/test/conformance/cases/terms/extra_arg_atom_fails.eye +1 -1
  44. package/test/conformance/cases/terms/extra_arg_zero_fails.eye +1 -1
  45. package/test/conformance/cases/terms/extra_compound_name_arguments_bad_args_fails.eye +1 -1
  46. package/test/conformance/cases/variables/007_anonymous_variables.eye +1 -1
  47. package/test/conformance/cases/variables/026_question_underscore_named_variable_reuse.eye +1 -1
  48. package/test/conformance/cases/variables/anonymous_in_two_goals.eye +2 -2
  49. package/test/conformance/cases/variables/extra_anonymous_not_reused.eye +1 -1
  50. package/test/conformance/cases/variables/question_anonymous_not_reused.eye +3 -3
  51. package/test/conformance/expected-errors/syntax/bad_question_digit_variable.txt +1 -1
  52. package/test/conformance/expected-errors/variables/question_digit_rejected.txt +1 -1
  53. package/test/run-regression.mjs +2 -2
package/docs/guide.md CHANGED
@@ -360,9 +360,9 @@ Use `holds/2` when you want to match the member term directly, for example `name
360
360
  | [`derived-backward-rule.eye`](../examples/derived-backward-rule.eye) | Derives an inverse-property backward rule from rule data. | [`output/derived-backward-rule.eye`](../examples/output/derived-backward-rule.eye) |
361
361
  | [`derived-rule.eye`](../examples/derived-rule.eye) | Derives conclusions from rule data. | [`output/derived-rule.eye`](../examples/output/derived-rule.eye) |
362
362
  | [`diamond-property.eye`](../examples/diamond-property.eye) | Checks the diamond property of a relation. | [`output/diamond-property.eye`](../examples/output/diamond-property.eye) |
363
- | [`dijkstra.eye`](../examples/dijkstra.eye) | Enumerates weighted simple paths. | [`output/dijkstra.eye`](../examples/output/dijkstra.eye) |
364
363
  | [`dijkstra-findall-sort.eye`](../examples/dijkstra-findall-sort.eye) | Finds shortest paths using collected candidates. | [`output/dijkstra-findall-sort.eye`](../examples/output/dijkstra-findall-sort.eye) |
365
364
  | [`dijkstra-risk-path.eye`](../examples/dijkstra-risk-path.eye) | Ranks routes by cost and trust. | [`output/dijkstra-risk-path.eye`](../examples/output/dijkstra-risk-path.eye) |
365
+ | [`dijkstra.eye`](../examples/dijkstra.eye) | Enumerates weighted simple paths. | [`output/dijkstra.eye`](../examples/output/dijkstra.eye) |
366
366
  | [`dining-philosophers.eye`](../examples/dining-philosophers.eye) | Simulates Chandy-Misra fork exchanges. | [`output/dining-philosophers.eye`](../examples/output/dining-philosophers.eye) |
367
367
  | [`dog.eye`](../examples/dog.eye) | Counts dogs and derives when a license is required. | [`output/dog.eye`](../examples/output/dog.eye) |
368
368
  | [`dpv-odrl-purpose-mapping.eye`](../examples/dpv-odrl-purpose-mapping.eye) | Maps a DPV process into an ODRL permission view. | [`output/dpv-odrl-purpose-mapping.eye`](../examples/output/dpv-odrl-purpose-mapping.eye) |
@@ -389,8 +389,8 @@ Use `holds/2` when you want to match the member term directly, for example `name
389
389
  | [`gdpr-compliance.eye`](../examples/gdpr-compliance.eye) | Checks GDPR-style processing compliance. | [`output/gdpr-compliance.eye`](../examples/output/gdpr-compliance.eye) |
390
390
  | [`good-cobbler.eye`](../examples/good-cobbler.eye) | Demonstrates term-level structure with a good-cobbler statement. | [`output/good-cobbler.eye`](../examples/output/good-cobbler.eye) |
391
391
  | [`gps.eye`](../examples/gps.eye) | Finds and verifies route paths. | [`output/gps.eye`](../examples/output/gps.eye) |
392
- | [`graph.eye`](../examples/graph.eye) | Derives transitive paths over French-city road links while showing the productive recursive rule order. | [`output/graph.eye`](../examples/output/graph.eye) |
393
392
  | [`graph-reachability.eye`](../examples/graph-reachability.eye) | Derives reachable nodes in a graph. | [`output/graph-reachability.eye`](../examples/output/graph-reachability.eye) |
393
+ | [`graph.eye`](../examples/graph.eye) | Derives transitive paths over French-city road links while showing the productive recursive rule order. | [`output/graph.eye`](../examples/output/graph.eye) |
394
394
  | [`gray-code-counter.eye`](../examples/gray-code-counter.eye) | Generates Gray-code counter states. | [`output/gray-code-counter.eye`](../examples/output/gray-code-counter.eye) |
395
395
  | [`greatest-lower-bound-uniqueness.eye`](../examples/greatest-lower-bound-uniqueness.eye) | Shows uniqueness of greatest lower bounds in a finite order instance. | [`output/greatest-lower-bound-uniqueness.eye`](../examples/output/greatest-lower-bound-uniqueness.eye) |
396
396
  | [`group-inverse-uniqueness.eye`](../examples/group-inverse-uniqueness.eye) | Shows uniqueness of inverses in a finite group instance. | [`output/group-inverse-uniqueness.eye`](../examples/output/group-inverse-uniqueness.eye) |
@@ -398,6 +398,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
398
398
  | [`hamming-code.eye`](../examples/hamming-code.eye) | Corrects a single-bit Hamming word. | [`output/hamming-code.eye`](../examples/output/hamming-code.eye) |
399
399
  | [`hanoi.eye`](../examples/hanoi.eye) | Derives the Towers of Hanoi moves. | [`output/hanoi.eye`](../examples/output/hanoi.eye) |
400
400
  | [`heat-loss.eye`](../examples/heat-loss.eye) | Computes conductive heat loss. | [`output/heat-loss.eye`](../examples/output/heat-loss.eye) |
401
+ | [`herbrand-witnesses.eye`](../examples/herbrand-witnesses.eye) | Represents existential-style consequences as stable Herbrand witness terms. | [`output/herbrand-witnesses.eye`](../examples/output/herbrand-witnesses.eye) |
401
402
  | [`heron-theorem.eye`](../examples/heron-theorem.eye) | Computes triangle area by Heron's theorem. | [`output/heron-theorem.eye`](../examples/output/heron-theorem.eye) |
402
403
  | [`ideal-gas-law.eye`](../examples/ideal-gas-law.eye) | Applies the ideal gas law. | [`output/ideal-gas-law.eye`](../examples/output/ideal-gas-law.eye) |
403
404
  | [`illegitimate-reasoning.eye`](../examples/illegitimate-reasoning.eye) | Detects suspect reasoning patterns. | [`output/illegitimate-reasoning.eye`](../examples/output/illegitimate-reasoning.eye) |
@@ -413,7 +414,9 @@ Use `holds/2` when you want to match the member term directly, for example `name
413
414
  | [`list-collection.eye`](../examples/list-collection.eye) | Demonstrates list and collection built-ins. | [`output/list-collection.eye`](../examples/output/list-collection.eye) |
414
415
  | [`lldm.eye`](../examples/lldm.eye) | Calculates leg-length discrepancy measurements. | [`output/lldm.eye`](../examples/output/lldm.eye) |
415
416
  | [`manufacturing-quality-control.eye`](../examples/manufacturing-quality-control.eye) | Evaluates process capability and quality. | [`output/manufacturing-quality-control.eye`](../examples/output/manufacturing-quality-control.eye) |
417
+ | [`map-four-color-search.eye`](../examples/map-four-color-search.eye) | Searches for a valid four-colouring of the EU neighbour graph. | [`output/map-four-color-search.eye`](../examples/output/map-four-color-search.eye) |
416
418
  | [`matrix-chain-order.eye`](../examples/matrix-chain-order.eye) | Finds an optimal matrix-chain multiplication order. | [`output/matrix-chain-order.eye`](../examples/output/matrix-chain-order.eye) |
419
+ | [`matrix-noncommutativity.eye`](../examples/matrix-noncommutativity.eye) | Multiplies 2x2 matrices and shows non-commutativity. | [`output/matrix-noncommutativity.eye`](../examples/output/matrix-noncommutativity.eye) |
417
420
  | [`microgrid-dispatch.eye`](../examples/microgrid-dispatch.eye) | Plans microgrid dispatch and reserve. | [`output/microgrid-dispatch.eye`](../examples/output/microgrid-dispatch.eye) |
418
421
  | [`missionaries-cannibals.eye`](../examples/missionaries-cannibals.eye) | Solves the missionaries-and-cannibals river crossing puzzle. | [`output/missionaries-cannibals.eye`](../examples/output/missionaries-cannibals.eye) |
419
422
  | [`modal-logic-kripke.eye`](../examples/modal-logic-kripke.eye) | Emulates modal box and diamond operators over a finite Kripke frame. | [`output/modal-logic-kripke.eye`](../examples/output/modal-logic-kripke.eye) |
@@ -430,21 +433,24 @@ Use `holds/2` when you want to match the member term directly, for example `name
430
433
  | [`orbital-transfer-design.eye`](../examples/orbital-transfer-design.eye) | Designs a Hohmann orbital transfer. | [`output/orbital-transfer-design.eye`](../examples/output/orbital-transfer-design.eye) |
431
434
  | [`path-discovery.eye`](../examples/path-discovery.eye) | Discovers bounded air-route paths. | [`output/path-discovery.eye`](../examples/output/path-discovery.eye) |
432
435
  | [`peano-arithmetic.eye`](../examples/peano-arithmetic.eye) | Computes Peano addition, multiplication, and factorial. | [`output/peano-arithmetic.eye`](../examples/output/peano-arithmetic.eye) |
436
+ | [`peano-calculus.eye`](../examples/peano-calculus.eye) | Computes Peano addition, multiplication, and factorial. | [`output/peano-calculus.eye`](../examples/output/peano-calculus.eye) |
433
437
  | [`peasant.eye`](../examples/peasant.eye) | Performs peasant multiplication and exponentiation. | [`output/peasant.eye`](../examples/output/peasant.eye) |
434
438
  | [`pell-equation.eye`](../examples/pell-equation.eye) | Generates Pell-equation solutions by recurrence. | [`output/pell-equation.eye`](../examples/output/pell-equation.eye) |
435
439
  | [`pendulum-period.eye`](../examples/pendulum-period.eye) | Computes simple pendulum periods. | [`output/pendulum-period.eye`](../examples/output/pendulum-period.eye) |
436
440
  | [`polynomial.eye`](../examples/polynomial.eye) | Finds complex integer polynomial roots. | [`output/polynomial.eye`](../examples/output/polynomial.eye) |
441
+ | [`prime-range.eye`](../examples/prime-range.eye) | Finds primes in a finite range and computes a totient value. | [`output/prime-range.eye`](../examples/output/prime-range.eye) |
437
442
  | [`proof-contrapositive.eye`](../examples/proof-contrapositive.eye) | Models proof by contrapositive. | [`output/proof-contrapositive.eye`](../examples/output/proof-contrapositive.eye) |
438
443
  | [`quadratic-formula.eye`](../examples/quadratic-formula.eye) | Solves sample quadratic equations. | [`output/quadratic-formula.eye`](../examples/output/quadratic-formula.eye) |
439
444
  | [`radioactive-decay.eye`](../examples/radioactive-decay.eye) | Computes radioactive decay over time. | [`output/radioactive-decay.eye`](../examples/output/radioactive-decay.eye) |
440
445
  | [`reusable-builtins.eye`](../examples/reusable-builtins.eye) | Tours reusable numeric, list, and string builtins. | [`output/reusable-builtins.eye`](../examples/output/reusable-builtins.eye) |
441
446
  | [`riemann-hypothesis.eye`](../examples/riemann-hypothesis.eye) | Checks a finite catalogue of non-trivial zeta zeros against the Riemann-hypothesis condition. | [`output/riemann-hypothesis.eye`](../examples/output/riemann-hypothesis.eye) |
447
+ | [`route-planning.eye`](../examples/route-planning.eye) | Finds routes and records them as explicit route terms. | [`output/route-planning.eye`](../examples/output/route-planning.eye) |
442
448
  | [`security-incident-correlation.eye`](../examples/security-incident-correlation.eye) | Correlates security incidents across signals. | [`output/security-incident-correlation.eye`](../examples/output/security-incident-correlation.eye) |
443
449
  | [`send-more-money.eye`](../examples/send-more-money.eye) | Solves the SEND + MORE = MONEY cryptarithm. | [`output/send-more-money.eye`](../examples/output/send-more-money.eye) |
444
450
  | [`service-impact.eye`](../examples/service-impact.eye) | Analyzes service impact over cyclic dependencies. | [`output/service-impact.eye`](../examples/output/service-impact.eye) |
451
+ | [`shoelace-polygon-area.eye`](../examples/shoelace-polygon-area.eye) | Computes polygon area with a recursive shoelace calculation. | [`output/shoelace-polygon-area.eye`](../examples/output/shoelace-polygon-area.eye) |
445
452
  | [`sieve.eye`](../examples/sieve.eye) | Enumerates primes with a sieve-style program. | [`output/sieve.eye`](../examples/output/sieve.eye) |
446
453
  | [`skolem-functions.eye`](../examples/skolem-functions.eye) | Generates deterministic functional terms. | [`output/skolem-functions.eye`](../examples/output/skolem-functions.eye) |
447
- | [`herbrand-witnesses.eye`](../examples/herbrand-witnesses.eye) | Represents existential-style consequences as stable Herbrand witness terms. | [`output/herbrand-witnesses.eye`](../examples/output/herbrand-witnesses.eye) |
448
454
  | [`socket-age.eye`](../examples/socket-age.eye) | Shows socket-declared age reasoning inputs and plugs. | [`output/socket-age.eye`](../examples/output/socket-age.eye) |
449
455
  | [`socket-family.eye`](../examples/socket-family.eye) | Shows socket-declared family-source inputs and ancestry rules. | [`output/socket-family.eye`](../examples/output/socket-family.eye) |
450
456
  | [`socrates.eye`](../examples/socrates.eye) | Derives that Socrates is mortal. | [`output/socrates.eye`](../examples/output/socrates.eye) |
@@ -453,6 +459,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
453
459
  | [`stirling-bell-numbers.eye`](../examples/stirling-bell-numbers.eye) | Computes Stirling numbers and Bell numbers. | [`output/stirling-bell-numbers.eye`](../examples/output/stirling-bell-numbers.eye) |
454
460
  | [`sudoku-4x4.eye`](../examples/sudoku-4x4.eye) | Solves a compact 4x4 Sudoku by finite constraint search. | [`output/sudoku-4x4.eye`](../examples/output/sudoku-4x4.eye) |
455
461
  | [`superdense-coding.eye`](../examples/superdense-coding.eye) | Models superdense-coding bit transmission. | [`output/superdense-coding.eye`](../examples/output/superdense-coding.eye) |
462
+ | [`symbolic-derivative.eye`](../examples/symbolic-derivative.eye) | Symbolically differentiates explicit expression terms, including products and logs. | [`output/symbolic-derivative.eye`](../examples/output/symbolic-derivative.eye) |
456
463
  | [`term-tools.eye`](../examples/term-tools.eye) | Inspects, builds, renders, and validates terms with reusable term/control builtins. | [`output/term-tools.eye`](../examples/output/term-tools.eye) |
457
464
  | [`totient-summatory.eye`](../examples/totient-summatory.eye) | Computes Euler totients and their summatory function. | [`output/totient-summatory.eye`](../examples/output/totient-summatory.eye) |
458
465
  | [`trust-flow-provenance-threshold.eye`](../examples/trust-flow-provenance-threshold.eye) | Classifies message trust from provenance confidence scores. | [`output/trust-flow-provenance-threshold.eye`](../examples/output/trust-flow-provenance-threshold.eye) |
@@ -463,6 +470,7 @@ Use `holds/2` when you want to match the member term directly, for example `name
463
470
  | [`weighted-interval-scheduling.eye`](../examples/weighted-interval-scheduling.eye) | Selects the best non-overlapping weighted intervals with tabled dynamic programming. | [`output/weighted-interval-scheduling.eye`](../examples/output/weighted-interval-scheduling.eye) |
464
471
  | [`witch.eye`](../examples/witch.eye) | Derives the classic “burn the witch” rule chain. | [`output/witch.eye`](../examples/output/witch.eye) |
465
472
  | [`wolf-goat-cabbage.eye`](../examples/wolf-goat-cabbage.eye) | Solves the wolf-goat-cabbage river crossing. | [`output/wolf-goat-cabbage.eye`](../examples/output/wolf-goat-cabbage.eye) |
473
+ | [`workplace-compliance.eye`](../examples/workplace-compliance.eye) | Classifies workplace compliance from explicit action facts. | [`output/workplace-compliance.eye`](../examples/output/workplace-compliance.eye) |
466
474
  | [`zebra.eye`](../examples/zebra.eye) | Solves the zebra logic puzzle. | [`output/zebra.eye`](../examples/output/zebra.eye) |
467
475
 
468
476
  ## Golden outputs, tests, and conformance
@@ -123,7 +123,7 @@ A colon outside `:-` is not part of the language. Namespace-like names SHOULD be
123
123
 
124
124
  ### 3.4 Variables
125
125
 
126
- A variable starts with `?` followed by an ASCII letter or underscore and then zero or more ASCII letters, digits, or underscores. This N3/SPARQL-style spelling is the only source-level variable spelling in eyelang.
126
+ A variable is either the bare anonymous variable `?`, or starts with `?` followed by an ASCII letter or underscore and then zero or more ASCII letters, digits, or underscores. This N3/SPARQL-style spelling is the only source-level variable spelling in eyelang.
127
127
 
128
128
  Examples:
129
129
 
@@ -131,10 +131,10 @@ Examples:
131
131
  ?x
132
132
  ?person
133
133
  ?_thing
134
- ?_
134
+ ?
135
135
  ```
136
136
 
137
- Each `?_` anonymous variable occurrence is fresh. A bare `_` is not a variable in eyelang source.
137
+ Each bare `?` anonymous variable occurrence is fresh. A bare `_` is not a variable in eyelang source.
138
138
 
139
139
  ### 3.5 Atom constants
140
140
 
@@ -171,7 +171,7 @@ A quoted atom constant is enclosed in single quotes. A single quote inside a quo
171
171
  A graphic atom constant is one or more graphic characters from this set:
172
172
 
173
173
  ```text
174
- #$&*+-/<=>?@^~\
174
+ #$&*+-/<=>@^~\
175
175
  ```
176
176
 
177
177
  Angle-bracket IRI syntax is recognized only for absolute IRI-like contents. Graphic atoms such as `<=>`, `<`, and `>=` remain graphic atoms.
@@ -18,4 +18,4 @@ animal(?x) :- human(?x).
18
18
  type(joe, human) :- human(joe).
19
19
  type(joe, animal) :- animal(joe).
20
20
  subclassOf(human, animal) :- animal(human).
21
- succeeds(animalExample, true) :- animal(?_).
21
+ succeeds(animalExample, true) :- animal(?).
@@ -17,15 +17,15 @@ cow(grazing, 540, 18, 5.8, 21).
17
17
 
18
18
  % Maintenance scales with body weight; milk requirement scales with daily milk.
19
19
  maintenance(?c, ?m) :-
20
- cow(?c, ?weight, ?_, ?_, ?_),
20
+ cow(?c, ?weight, ?, ?, ?),
21
21
  mul(?weight, 0.08, ?m).
22
22
 
23
23
  milk_requirement(?c, ?r) :-
24
- cow(?c, ?_, ?milk, ?_, ?_),
24
+ cow(?c, ?, ?milk, ?, ?),
25
25
  mul(?milk, 5.0, ?r).
26
26
 
27
27
  ration_supply(?c, ?s) :-
28
- cow(?c, ?_, ?_, ?density, ?intake),
28
+ cow(?c, ?, ?, ?density, ?intake),
29
29
  mul(?density, ?intake, ?s).
30
30
 
31
31
  total_requirement(?c, ?r) :-
@@ -41,7 +41,7 @@ candidate(pathRelay, [depotA, relay, labD]).
41
41
  candidate(pathDirectC, [depotA, labD]).
42
42
  candidate(pathViaC, [depotA, depotC, depotB, labD]).
43
43
 
44
- route_cost([?_], 0.0, 0.0, 0).
44
+ route_cost([?], 0.0, 0.0, 0).
45
45
  route_cost([?from, ?to|?rest], ?raw, ?risk, ?edges) :-
46
46
  route_segment(?from, ?to, ?stepraw, ?steprisk),
47
47
  route_cost([?to|?rest], ?restraw, ?restrisk, ?restedges),
@@ -24,18 +24,18 @@ trip_data(cold_commute, 120, 90, -8, 100, 35, 0.19).
24
24
 
25
25
  % Each world adds a different combination of speed, temperature, payload, and
26
26
  % reserve factors before comparing required energy with usable battery.
27
- speed_factor(?t, 1.20) :- trip_data(?t, ?_, ?s, ?_, ?_, ?_, ?_), gt(?s, 100).
28
- speed_factor(?t, 1.00) :- trip_data(?t, ?_, ?s, ?_, ?_, ?_, ?_), le(?s, 100).
27
+ speed_factor(?t, 1.20) :- trip_data(?t, ?, ?s, ?, ?, ?, ?), gt(?s, 100).
28
+ speed_factor(?t, 1.00) :- trip_data(?t, ?, ?s, ?, ?, ?, ?), le(?s, 100).
29
29
 
30
- temperature_factor(?t, 1.15) :- trip_data(?t, ?_, ?_, ?temp, ?_, ?_, ?_), lt(?temp, 0).
31
- temperature_factor(?t, 1.00) :- trip_data(?t, ?_, ?_, ?temp, ?_, ?_, ?_), ge(?temp, 0).
30
+ temperature_factor(?t, 1.15) :- trip_data(?t, ?, ?, ?temp, ?, ?, ?), lt(?temp, 0).
31
+ temperature_factor(?t, 1.00) :- trip_data(?t, ?, ?, ?temp, ?, ?, ?), ge(?temp, 0).
32
32
 
33
- payload_factor(?t, 1.15) :- trip_data(?t, ?_, ?_, ?_, ?p, ?_, ?_), gt(?p, 500).
34
- payload_factor(?t, 1.08) :- trip_data(?t, ?_, ?_, ?_, ?p, ?_, ?_), gt(?p, 250), le(?p, 500).
35
- payload_factor(?t, 1.00) :- trip_data(?t, ?_, ?_, ?_, ?p, ?_, ?_), le(?p, 250).
33
+ payload_factor(?t, 1.15) :- trip_data(?t, ?, ?, ?, ?p, ?, ?), gt(?p, 500).
34
+ payload_factor(?t, 1.08) :- trip_data(?t, ?, ?, ?, ?p, ?, ?), gt(?p, 250), le(?p, 500).
35
+ payload_factor(?t, 1.00) :- trip_data(?t, ?, ?, ?, ?p, ?, ?), le(?p, 250).
36
36
 
37
37
  base_energy(?t, ?e) :-
38
- trip_data(?t, ?d, ?_, ?_, ?_, ?_, ?b),
38
+ trip_data(?t, ?d, ?, ?, ?, ?, ?b),
39
39
  mul(?d, ?b, ?e).
40
40
 
41
41
  required_energy(?t, w1, ?e) :-
@@ -61,12 +61,12 @@ required_energy(?t, w3, ?e) :-
61
61
 
62
62
  % safe_in_world/2 compares required trip energy with usable battery capacity.
63
63
  safe_in_world(?t, ?w) :-
64
- trip_data(?t, ?_, ?_, ?_, ?_, ?battery, ?_),
64
+ trip_data(?t, ?, ?, ?, ?, ?battery, ?),
65
65
  required_energy(?t, ?w, ?required),
66
66
  le(?required, ?battery).
67
67
 
68
68
  risky_in_world(?t, ?w) :-
69
- trip_data(?t, ?_, ?_, ?_, ?_, ?battery, ?_),
69
+ trip_data(?t, ?, ?, ?, ?, ?battery, ?),
70
70
  required_energy(?t, ?w, ?required),
71
71
  gt(?required, ?battery).
72
72
 
@@ -82,4 +82,4 @@ fft(?wave, ?spectrum) :-
82
82
 
83
83
  dcComponent(?wave, ?dc) :-
84
84
  wave(?wave, ?samples),
85
- fft8(?samples, [?dc|?_]).
85
+ fft8(?samples, [?dc|?]).
@@ -21,41 +21,41 @@ field(clay_surplus, 70, 90, 0.08, 120).
21
21
  % total_n/2 and available_n/2 build the nutrient budget; surplus/deficit and
22
22
  % leaching rules then explain the resulting field status.
23
23
  total_n(?f, ?total) :-
24
- field(?f, ?soil, ?fert, ?_, ?_),
24
+ field(?f, ?soil, ?fert, ?, ?),
25
25
  add(?soil, ?fert, ?total).
26
26
 
27
27
  available_n(?f, ?avail) :-
28
28
  total_n(?f, ?total),
29
- field(?f, ?_, ?_, ?loss, ?_),
29
+ field(?f, ?, ?, ?loss, ?),
30
30
  sub(1.0, ?loss, ?retained),
31
31
  mul(?total, ?retained, ?avail).
32
32
 
33
33
  % surplus_n/2 and deficit_n/2 split the signed balance into reportable quantities.
34
34
  surplus_n(?f, ?surplus) :-
35
35
  available_n(?f, ?avail),
36
- field(?f, ?_, ?_, ?_, ?demand),
36
+ field(?f, ?, ?, ?, ?demand),
37
37
  gt(?avail, ?demand),
38
38
  sub(?avail, ?demand, ?surplus).
39
39
 
40
40
  surplus_n(?f, 0.0) :-
41
41
  available_n(?f, ?avail),
42
- field(?f, ?_, ?_, ?_, ?demand),
42
+ field(?f, ?, ?, ?, ?demand),
43
43
  le(?avail, ?demand).
44
44
 
45
45
  deficit_n(?f, ?deficit) :-
46
46
  available_n(?f, ?avail),
47
- field(?f, ?_, ?_, ?_, ?demand),
47
+ field(?f, ?, ?, ?, ?demand),
48
48
  lt(?avail, ?demand),
49
49
  sub(?demand, ?avail, ?deficit).
50
50
 
51
51
  deficit_n(?f, 0.0) :-
52
52
  available_n(?f, ?avail),
53
- field(?f, ?_, ?_, ?_, ?demand),
53
+ field(?f, ?, ?, ?, ?demand),
54
54
  ge(?avail, ?demand).
55
55
 
56
56
  leaching_index(?f, ?index) :-
57
57
  surplus_n(?f, ?surplus),
58
- field(?f, ?_, ?_, ?loss, ?_),
58
+ field(?f, ?, ?, ?loss, ?),
59
59
  mul(?surplus, ?loss, ?index).
60
60
 
61
61
  status(?f, under_supplied) :- deficit_n(?f, ?d), gt(?d, 10.0).
@@ -112,8 +112,8 @@ distinctPrimeCount(case, 4) :-
112
112
 
113
113
  smallestPrimeFactor(case, 3) :-
114
114
  case(fta, ?n),
115
- factor_smallest(?n, [3|?_]).
115
+ factor_smallest(?n, [3|?]).
116
116
 
117
117
  largestPrimeFactor(case, 3881) :-
118
118
  case(fta, ?n),
119
- factor_largest(?n, [3881|?_]).
119
+ factor_largest(?n, [3881|?]).
package/examples/gps.eye CHANGED
@@ -78,24 +78,24 @@ outcome(routeDirect, "Take the direct route via Brugge.").
78
78
 
79
79
  % Verification checks, analogous to the false-producing guards in gps.n3.
80
80
  check(c1, true) :-
81
- traveller_path(i1, [drive_gent_brugge, drive_brugge_oostende], ?_, ?_, ?_, ?_).
81
+ traveller_path(i1, [drive_gent_brugge, drive_brugge_oostende], ?, ?, ?, ?).
82
82
 
83
83
  check(c2, true) :-
84
- traveller_path(i1, [drive_gent_kortrijk, drive_kortrijk_brugge, drive_brugge_oostende], ?_, ?_, ?_, ?_).
84
+ traveller_path(i1, [drive_gent_kortrijk, drive_kortrijk_brugge, drive_brugge_oostende], ?, ?, ?, ?).
85
85
 
86
86
  check(c3, true) :-
87
- route_metrics(routeDirect, ?d1, ?_, ?_, ?_),
88
- route_metrics(routeViaKortrijk, ?d2, ?_, ?_, ?_),
87
+ route_metrics(routeDirect, ?d1, ?, ?, ?),
88
+ route_metrics(routeViaKortrijk, ?d2, ?, ?, ?),
89
89
  lt(?d1, ?d2).
90
90
 
91
91
  check(c4, true) :-
92
- route_metrics(routeDirect, ?_, ?c1, ?_, ?_),
93
- route_metrics(routeViaKortrijk, ?_, ?c2, ?_, ?_),
92
+ route_metrics(routeDirect, ?, ?c1, ?, ?),
93
+ route_metrics(routeViaKortrijk, ?, ?c2, ?, ?),
94
94
  lt(?c1, ?c2).
95
95
 
96
96
  check(c5, true) :-
97
- route_metrics(routeDirect, ?_, ?_, ?b1, ?f1),
98
- route_metrics(routeViaKortrijk, ?_, ?_, ?b2, ?f2),
97
+ route_metrics(routeDirect, ?, ?, ?b1, ?f1),
98
+ route_metrics(routeViaKortrijk, ?, ?, ?b2, ?f2),
99
99
  gt(?b1, ?b2),
100
100
  gt(?f1, ?f2).
101
101
 
@@ -67,22 +67,22 @@ fallacy(?a, hasty_generalization) :-
67
67
  sample_size(?a, ?n),
68
68
  required_sample_size(?a, ?min),
69
69
  lt(?n, ?min),
70
- concludes(?a, all(?_, ?_)).
70
+ concludes(?a, all(?, ?)).
71
71
 
72
72
  fallacy(?a, false_dilemma) :-
73
73
  argument(?a),
74
- presented_alternatives(?a, ?_),
75
- omitted_alternative(?a, ?_),
76
- concludes(?a, ?_).
74
+ presented_alternatives(?a, ?),
75
+ omitted_alternative(?a, ?),
76
+ concludes(?a, ?).
77
77
 
78
78
  reason(arg_affirming_consequent, "observing the consequent does not prove the antecedent").
79
79
  reason(arg_denying_antecedent, "denying the antecedent does not disprove the consequent").
80
80
  reason(arg_hasty_generalization, "sample size is below the threshold for a universal conclusion").
81
81
  reason(arg_false_dilemma, "a relevant alternative is omitted").
82
82
 
83
- type(?a, illegitimate_reasoning) :- fallacy(?a, ?_).
84
- conclusion(?a, ?c) :- fallacy(?a, ?_), concludes(?a, ?c).
85
- reason(?a, ?r) :- fallacy(?a, ?_), reason(?a, ?r).
83
+ type(?a, illegitimate_reasoning) :- fallacy(?a, ?).
84
+ conclusion(?a, ?c) :- fallacy(?a, ?), concludes(?a, ?c).
85
+ reason(?a, ?r) :- fallacy(?a, ?), reason(?a, ?r).
86
86
  sampleSize(?a, ?n) :- fallacy(?a, hasty_generalization), sample_size(?a, ?n).
87
87
  requiredSampleSize(?a, ?min) :- fallacy(?a, hasty_generalization), required_sample_size(?a, ?min).
88
88
  omittedAlternative(?a, ?alt) :- fallacy(?a, false_dilemma), omitted_alternative(?a, ?alt).
@@ -0,0 +1,65 @@
1
+ % Four-colour search for the European Union neighbour graph.
2
+ %
3
+ % This is a finite executable version of the source map-colouring example. The
4
+ % neighbour facts are the EU country graph from the original input, represented
5
+ % with lowercase atom names. `once/1` asks for one valid colouring rather than
6
+ % enumerating all possible four-colour assignments.
7
+
8
+ materialize(four_color_answer, 2).
9
+
10
+ color(red).
11
+ color(green).
12
+ color(blue).
13
+ color(yellow).
14
+
15
+ place_order([belgium, netherlands, luxemburg, france, germany, italy, denmark, ireland, greece, spain, portugal, austria, sweden, finland, cyprus, malta, poland, hungary, czech_republic, slovakia, slovenia, estonia, latvia, lithuania, bulgaria, romania, croatia]).
16
+
17
+ neighbours(belgium, [france, netherlands, luxemburg, germany]).
18
+ neighbours(netherlands, [belgium, germany]).
19
+ neighbours(luxemburg, [belgium, france, germany]).
20
+ neighbours(france, [spain, belgium, luxemburg, germany, italy]).
21
+ neighbours(germany, [netherlands, belgium, luxemburg, denmark, france, austria, poland, czech_republic]).
22
+ neighbours(italy, [france, austria, slovenia]).
23
+ neighbours(denmark, [germany]).
24
+ neighbours(ireland, []).
25
+ neighbours(greece, [bulgaria]).
26
+ neighbours(spain, [france, portugal]).
27
+ neighbours(portugal, [spain]).
28
+ neighbours(austria, [czech_republic, germany, hungary, italy, slovenia, slovakia]).
29
+ neighbours(sweden, [finland]).
30
+ neighbours(finland, [sweden]).
31
+ neighbours(cyprus, []).
32
+ neighbours(malta, []).
33
+ neighbours(poland, [germany, czech_republic, slovakia, lithuania]).
34
+ neighbours(hungary, [austria, slovakia, romania, croatia, slovenia]).
35
+ neighbours(czech_republic, [germany, poland, slovakia, austria]).
36
+ neighbours(slovakia, [czech_republic, poland, hungary, austria]).
37
+ neighbours(slovenia, [austria, italy, hungary, croatia]).
38
+ neighbours(estonia, [latvia]).
39
+ neighbours(latvia, [estonia, lithuania]).
40
+ neighbours(lithuania, [latvia, poland]).
41
+ neighbours(bulgaria, [romania, greece]).
42
+ neighbours(romania, [hungary, bulgaria]).
43
+ neighbours(croatia, [slovenia, hungary]).
44
+
45
+ % Colour the tail first, like the source Prolog program. That gives each
46
+ % colour choice the already-coloured suffix to check against and avoids
47
+ % generating many doomed prefixes.
48
+ valid_color(?place, ?color, ?assigned) :-
49
+ neighbours(?place, ?neighbors),
50
+ not((member([?neighbor, ?color], ?assigned), member(?neighbor, ?neighbors))).
51
+
52
+ place_pairs([], []).
53
+ place_pairs([?place|?rest], [[?place, ?]|?pairs]) :-
54
+ place_pairs(?rest, ?pairs).
55
+
56
+ color_places([]).
57
+ color_places([[?place, ?color]|?tail]) :-
58
+ color_places(?tail),
59
+ color(?color),
60
+ valid_color(?place, ?color, ?tail).
61
+
62
+ four_color_answer(european_union, ?coloring) :-
63
+ place_order(?places),
64
+ place_pairs(?places, ?coloring),
65
+ once(color_places(?coloring)).
@@ -0,0 +1,43 @@
1
+ % Matrix multiplication and non-commutativity.
2
+ %
3
+ % The original matrix example contains a larger matrix library. This compact
4
+ % Eyelang case keeps the core operation visible: multiply two 2x2 matrices and
5
+ % show that, in general, A*B is not the same matrix as B*A.
6
+
7
+ materialize(matrix_result, 2).
8
+
9
+ matrix_a([[1, 2], [0, 1]]).
10
+ matrix_b([[1, 0], [3, 1]]).
11
+
12
+ dot2([?x1, ?x2], [?y1, ?y2], ?r) :-
13
+ mul(?x1, ?y1, ?p1),
14
+ mul(?x2, ?y2, ?p2),
15
+ add(?p1, ?p2, ?r).
16
+
17
+ transpose2([[?a, ?b], [?c, ?d]], [[?a, ?c], [?b, ?d]]).
18
+
19
+ row_times_matrix(?row, ?matrix, [?r1, ?r2]) :-
20
+ transpose2(?matrix, [?col1, ?col2]),
21
+ dot2(?row, ?col1, ?r1),
22
+ dot2(?row, ?col2, ?r2).
23
+
24
+ matrix_mul([?row1, ?row2], ?matrix, [?out1, ?out2]) :-
25
+ row_times_matrix(?row1, ?matrix, ?out1),
26
+ row_times_matrix(?row2, ?matrix, ?out2).
27
+
28
+ matrix_result(ab, ?ab) :-
29
+ matrix_a(?a),
30
+ matrix_b(?b),
31
+ matrix_mul(?a, ?b, ?ab).
32
+
33
+ matrix_result(ba, ?ba) :-
34
+ matrix_a(?a),
35
+ matrix_b(?b),
36
+ matrix_mul(?b, ?a, ?ba).
37
+
38
+ matrix_result(commutative, false) :-
39
+ matrix_a(?a),
40
+ matrix_b(?b),
41
+ matrix_mul(?a, ?b, ?ab),
42
+ matrix_mul(?b, ?a, ?ba),
43
+ neq(?ab, ?ba).
@@ -19,9 +19,9 @@ plan(?moves) :-
19
19
  goal_state(?g),
20
20
  reachable(?i, ?moves, ?g).
21
21
 
22
- candidate_plan([?_, ?_, ?_]).
23
- candidate_plan([?_, ?_, ?_, ?_]).
24
- candidate_plan([?_, ?_, ?_, ?_, ?_]).
22
+ candidate_plan([?, ?, ?]).
23
+ candidate_plan([?, ?, ?, ?]).
24
+ candidate_plan([?, ?, ?, ?, ?]).
25
25
 
26
26
  reachable(?s, [], ?s).
27
27
  reachable(?s1, [?m|?l], ?s3) :-
@@ -29,7 +29,7 @@ reachable(?s1, [?m|?l], ?s3) :-
29
29
  reachable(?s2, ?l, ?s3).
30
30
 
31
31
  initial_state([loc1, loc2, loc3, n, n]).
32
- goal_state([?_, ?_, ?_, ?_, y]).
32
+ goal_state([?, ?, ?, ?, y]).
33
33
 
34
34
  legal_move([?b, ?m, ?m, n, ?h], climb_on, [?b, ?m, ?m, y, ?h]).
35
35
  legal_move([?b, ?m, ?m, y, ?h], climb_off, [?b, ?m, ?m, n, ?h]).
@@ -0,0 +1 @@
1
+ four_color_answer(european_union, [[belgium, yellow], [netherlands, green], [luxemburg, green], [france, blue], [germany, red], [italy, red], [denmark, green], [ireland, red], [greece, red], [spain, green], [portugal, red], [austria, yellow], [sweden, green], [finland, red], [cyprus, red], [malta, red], [poland, blue], [hungary, blue], [czech_republic, green], [slovakia, red], [slovenia, green], [estonia, red], [latvia, green], [lithuania, red], [bulgaria, green], [romania, red], [croatia, red]]).
@@ -0,0 +1,3 @@
1
+ matrix_result(ab, [[7, 2], [3, 1]]).
2
+ matrix_result(ba, [[1, 2], [3, 7]]).
3
+ matrix_result(commutative, false).
@@ -0,0 +1,3 @@
1
+ peano_answer(two_plus_three, s(s(s(s(s(z)))))).
2
+ peano_answer(two_times_three, s(s(s(s(s(s(z))))))).
3
+ peano_answer(factorial_four, s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(s(z))))))))))))))))))))))))).
@@ -0,0 +1,3 @@
1
+ prime_result(range_2_30, [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]).
2
+ prime_result(count_2_30, 10).
3
+ prime_result(totient_271, 270).
@@ -0,0 +1,4 @@
1
+ route_to_nantes(angers, go(angers, nantes, goal)).
2
+ route_to_nantes(paris, go(paris, chartres, go(chartres, lemans, go(lemans, angers, go(angers, nantes, goal))))).
3
+ route_to_nantes(chartres, go(chartres, lemans, go(lemans, angers, go(angers, nantes, goal)))).
4
+ route_to_nantes(lemans, go(lemans, angers, go(angers, nantes, goal))).
@@ -0,0 +1 @@
1
+ polygon_area(sample, 7.5).
@@ -0,0 +1,4 @@
1
+ derivative_result(square, add(mul(const(1), var(x)), mul(var(x), const(1)))).
2
+ derivative_result(linear_plus_const, add(const(1), const(0))).
3
+ derivative_result(product, add(mul(add(const(1), const(0)), mul(add(pow(var(x), 2), const(2)), add(pow(var(x), 3), const(3)))), mul(add(var(x), const(1)), add(mul(add(mul(mul(const(2), pow(var(x), 1)), const(1)), const(0)), add(pow(var(x), 3), const(3))), mul(add(pow(var(x), 2), const(2)), add(mul(mul(const(3), pow(var(x), 2)), const(1)), const(0))))))).
4
+ derivative_result(nested_log, divide(divide(const(1), var(x)), log(var(x)))).
@@ -0,0 +1,4 @@
1
+ status(bob, compliant).
2
+ status(alice, compliant).
3
+ status(dave, non_compliant).
4
+ status(carol, non_compliant).
@@ -0,0 +1,40 @@
1
+ % Peano addition, multiplication, and factorial over explicit Herbrand terms.
2
+ %
3
+ % The original logic-programming example uses `0` and `s(...)`. Here zero is
4
+ % the atom `z`, so every natural number is an ordinary Eyelang term: z, s(z),
5
+ % s(s(z)), and so on. The rules are relational; the materialized facts choose
6
+ % a few finite calculations as readable examples.
7
+
8
+ materialize(peano_answer, 2).
9
+ table(padd, 3).
10
+ table(pmul, 3).
11
+ table(pfact, 2).
12
+
13
+ % Addition.
14
+ padd(?a, z, ?a).
15
+ padd(?a, s(?b), s(?c)) :-
16
+ padd(?a, ?b, ?c).
17
+
18
+ % Multiplication by repeated addition.
19
+ pmul(?_a, z, z).
20
+ pmul(?a, s(?b), ?c) :-
21
+ pmul(?a, ?b, ?d),
22
+ padd(?a, ?d, ?c).
23
+
24
+ % Factorial with an accumulator.
25
+ pfact(?n, ?value) :-
26
+ pfac(?n, s(z), ?value).
27
+
28
+ pfac(z, ?acc, ?acc).
29
+ pfac(s(?n), ?acc, ?value) :-
30
+ pmul(?acc, s(?n), ?next),
31
+ pfac(?n, ?next, ?value).
32
+
33
+ peano_answer(two_plus_three, ?n) :-
34
+ padd(s(s(z)), s(s(s(z))), ?n).
35
+
36
+ peano_answer(two_times_three, ?n) :-
37
+ pmul(s(s(z)), s(s(s(z))), ?n).
38
+
39
+ peano_answer(factorial_four, ?n) :-
40
+ pfact(s(s(s(s(z)))), ?n).
@@ -0,0 +1,45 @@
1
+ % Prime ranges and Euler totient over finite integer domains.
2
+ %
3
+ % The source example combines prime search with Euler's totient function. This
4
+ % Eyelang version keeps the computation finite and declarative: composite
5
+ % numbers are described by proper divisors, primes are candidates that are not
6
+ % composite, and `totient/2` counts numbers coprime with the input.
7
+
8
+ materialize(prime_result, 2).
9
+ table(gcd, 3).
10
+
11
+ candidate(?n) :-
12
+ between(2, 30, ?n).
13
+
14
+ composite(?n) :-
15
+ candidate(?n),
16
+ between(2, ?n, ?d),
17
+ lt(?d, ?n),
18
+ mod(?n, ?d, 0).
19
+
20
+ prime(?n) :-
21
+ candidate(?n),
22
+ not(composite(?n)).
23
+
24
+ % Euclid's algorithm, used for the totient calculation.
25
+ gcd(?n, 0, ?n).
26
+ gcd(?n, ?m, ?g) :-
27
+ gt(?m, 0),
28
+ mod(?n, ?m, ?r),
29
+ gcd(?m, ?r, ?g).
30
+
31
+ coprime(?n, ?k) :-
32
+ between(1, ?n, ?k),
33
+ gcd(?n, ?k, 1).
34
+
35
+ totient(?n, ?phi) :-
36
+ countall(coprime(?n, ?_k), ?phi).
37
+
38
+ prime_result(range_2_30, ?primes) :-
39
+ findall(?p, prime(?p), ?primes).
40
+
41
+ prime_result(count_2_30, ?count) :-
42
+ countall(prime(?p), ?count).
43
+
44
+ prime_result(totient_271, ?phi) :-
45
+ totient(271, ?phi).
@@ -0,0 +1,33 @@
1
+ % Route planning with explicit route terms.
2
+ %
3
+ % This is the Eyelang version of the classic Paris-to-Nantes path example: the
4
+ % facts describe one-way road links, and `path/2` derives both the endpoint pair
5
+ % and a structured `go(..., ..., ...)` plan. The plan is ordinary data, so the
6
+ % route can be inspected, stored, or used by later rules.
7
+
8
+ materialize(route_to_nantes, 2).
9
+ table(path, 2).
10
+ mode(path, 2, [in, out]).
11
+
12
+ oneway(paris, orleans).
13
+ oneway(paris, chartres).
14
+ oneway(paris, amiens).
15
+ oneway(orleans, blois).
16
+ oneway(orleans, bourges).
17
+ oneway(blois, tours).
18
+ oneway(chartres, lemans).
19
+ oneway(lemans, angers).
20
+ oneway(lemans, tours).
21
+ oneway(angers, nantes).
22
+
23
+ % A direct edge is a one-step plan.
24
+ path([?a, ?b], go(?a, ?b, goal)) :-
25
+ oneway(?a, ?b).
26
+
27
+ % A longer path prepends one edge to the remaining plan.
28
+ path([?a, ?c], go(?a, ?b, ?rest)) :-
29
+ oneway(?a, ?b),
30
+ path([?b, ?c], ?rest).
31
+
32
+ route_to_nantes(?from, ?plan) :-
33
+ path([?from, nantes], ?plan).
@@ -0,0 +1,22 @@
1
+ % Polygon area by the shoelace formula.
2
+ %
3
+ % The input polygon is the same closed polygon shape used by the source example:
4
+ % the final point repeats the first point. Each recursive step consumes one
5
+ % adjacent pair and contributes `(x1*y2 - y1*x2) / 2` to the oriented area.
6
+
7
+ materialize(polygon_area, 2).
8
+
9
+ sample_polygon([[3, 2], [6, 2], [7, 6], [4, 6], [5, 5], [5, 3], [3, 2]]).
10
+
11
+ area([?_point], 0).
12
+ area([[?a, ?b], [?c, ?d]|?rest], ?total) :-
13
+ area([[?c, ?d]|?rest], ?subtotal),
14
+ mul(?a, ?d, ?ad),
15
+ mul(?b, ?c, ?bc),
16
+ sub(?ad, ?bc, ?cross),
17
+ div(?cross, 2.0, ?half),
18
+ add(?half, ?subtotal, ?total).
19
+
20
+ polygon_area(sample, ?area) :-
21
+ sample_polygon(?points),
22
+ area(?points, ?area).
@@ -0,0 +1,39 @@
1
+ % Symbolic differentiation over explicit expression terms.
2
+ %
3
+ % The source derivative example uses Prolog operators such as `+`, `*`, `^`, and
4
+ % cut. Eyelang keeps expressions as ordinary terms: `add/2`, `mul/2`, `pow/2`,
5
+ % `log/1`, and so on. The result is intentionally unsimplified so the rule that
6
+ % produced each part remains visible.
7
+
8
+ materialize(derivative_result, 2).
9
+
10
+ expr(square, mul(var(x), var(x))).
11
+ expr(linear_plus_const, add(var(x), const(3))).
12
+ expr(product, mul(add(var(x), const(1)), mul(add(pow(var(x), 2), const(2)), add(pow(var(x), 3), const(3))))).
13
+ expr(nested_log, log(log(var(x)))).
14
+
15
+ d(const(?_c), ?_x, const(0)).
16
+ d(var(?x), ?x, const(1)).
17
+ d(var(?y), ?x, const(0)) :-
18
+ neq(?x, ?y).
19
+ d(add(?u, ?v), ?x, add(?du, ?dv)) :-
20
+ d(?u, ?x, ?du),
21
+ d(?v, ?x, ?dv).
22
+ d(sub(?u, ?v), ?x, sub(?du, ?dv)) :-
23
+ d(?u, ?x, ?du),
24
+ d(?v, ?x, ?dv).
25
+ d(mul(?u, ?v), ?x, add(mul(?du, ?v), mul(?u, ?dv))) :-
26
+ d(?u, ?x, ?du),
27
+ d(?v, ?x, ?dv).
28
+ d(divide(?u, ?v), ?x, divide(sub(mul(?du, ?v), mul(?u, ?dv)), pow(?v, 2))) :-
29
+ d(?u, ?x, ?du),
30
+ d(?v, ?x, ?dv).
31
+ d(pow(?u, ?n), ?x, mul(mul(const(?n), pow(?u, ?n1)), ?du)) :-
32
+ sub(?n, 1, ?n1),
33
+ d(?u, ?x, ?du).
34
+ d(log(?u), ?x, divide(?du, ?u)) :-
35
+ d(?u, ?x, ?du).
36
+
37
+ derivative_result(?name, ?derivative) :-
38
+ expr(?name, ?expr),
39
+ d(?expr, x, ?derivative).
@@ -46,8 +46,8 @@ safe([?man, ?wolf, ?goat, ?cabbage]) :-
46
46
  one_eq(?man, ?goat, ?wolf),
47
47
  one_eq(?man, ?goat, ?cabbage).
48
48
 
49
- one_eq(?x, ?x, ?_).
50
- one_eq(?x, ?_, ?x).
49
+ one_eq(?x, ?x, ?).
50
+ one_eq(?x, ?, ?x).
51
51
 
52
52
  solution(puzzle, ?moves) :-
53
53
  solution(?moves).
@@ -0,0 +1,41 @@
1
+ % Workplace compliance from explicit action facts.
2
+ %
3
+ % The source example generated a large dynamic dataset. Eyelang keeps the data
4
+ % explicit and reproducible: each `does/2` fact records an observed employee
5
+ % action, and the rules classify compliant and non-compliant behaviour.
6
+
7
+ materialize(status, 2).
8
+
9
+ employee(alice).
10
+ employee(bob).
11
+ employee(carol).
12
+ employee(dave).
13
+
14
+ does(alice, log_off_at_end_of_shift).
15
+ does(bob, work_related_task).
16
+ does(bob, log_off_at_end_of_shift).
17
+ does(carol, access_social_media).
18
+ does(dave, work_related_task).
19
+
20
+ % Work-related activity is compliant when the employee also logs off.
21
+ status(?person, compliant) :-
22
+ employee(?person),
23
+ does(?person, work_related_task),
24
+ does(?person, log_off_at_end_of_shift).
25
+
26
+ % Logging off is compliant by itself when no work task was observed.
27
+ status(?person, compliant) :-
28
+ employee(?person),
29
+ does(?person, log_off_at_end_of_shift),
30
+ not(does(?person, work_related_task)).
31
+
32
+ % A work task without the required log-off is non-compliant.
33
+ status(?person, non_compliant) :-
34
+ employee(?person),
35
+ does(?person, work_related_task),
36
+ not(does(?person, log_off_at_end_of_shift)).
37
+
38
+ % Accessing social media is non-compliant in this policy.
39
+ status(?person, non_compliant) :-
40
+ employee(?person),
41
+ does(?person, access_social_media).
@@ -12,33 +12,33 @@ materialize(solved, 2).
12
12
 
13
13
  % The single zebra/2 rule is a finite constraint model over the five house slots.
14
14
  zebra(?waterdrinker, ?zebraowner) :-
15
- eq(?houses, [?_, ?_, ?_, ?_, ?_]),
16
- first(?houses, house(?_, norwegian, ?_, ?_, ?_)),
17
- third(?houses, house(?_, ?_, ?_, milk, ?_)),
18
- adjacent(house(?_, norwegian, ?_, ?_, ?_), house(blue, ?_, ?_, ?_, ?_), ?houses),
19
- next_to(house(ivory, ?_, ?_, ?_, ?_), house(green, ?_, ?_, ?_, ?_), ?houses),
20
- member(house(red, english, ?_, ?_, ?_), ?houses),
21
- member(house(green, ?_, ?_, coffee, ?_), ?houses),
22
- member(house(yellow, ?_, ?_, ?_, kools), ?houses),
23
- member(house(?_, spanish, dog, ?_, ?_), ?houses),
24
- member(house(?_, ukrainian, ?_, tea, ?_), ?houses),
25
- member(house(?_, ?_, snail, ?_, old_gold), ?houses),
26
- adjacent(house(?_, ?_, ?_, ?_, chesterfields), house(?_, ?_, fox, ?_, ?_), ?houses),
27
- adjacent(house(?_, ?_, ?_, ?_, kools), house(?_, ?_, horse, ?_, ?_), ?houses),
28
- member(house(?_, ?_, ?_, orange_juice, lucky_strike), ?houses),
29
- member(house(?_, japanese, ?_, ?_, parliaments), ?houses),
30
- member(house(?_, ?waterdrinker, ?_, water, ?_), ?houses),
31
- member(house(?_, ?zebraowner, zebra, ?_, ?_), ?houses).
15
+ eq(?houses, [?, ?, ?, ?, ?]),
16
+ first(?houses, house(?, norwegian, ?, ?, ?)),
17
+ third(?houses, house(?, ?, ?, milk, ?)),
18
+ adjacent(house(?, norwegian, ?, ?, ?), house(blue, ?, ?, ?, ?), ?houses),
19
+ next_to(house(ivory, ?, ?, ?, ?), house(green, ?, ?, ?, ?), ?houses),
20
+ member(house(red, english, ?, ?, ?), ?houses),
21
+ member(house(green, ?, ?, coffee, ?), ?houses),
22
+ member(house(yellow, ?, ?, ?, kools), ?houses),
23
+ member(house(?, spanish, dog, ?, ?), ?houses),
24
+ member(house(?, ukrainian, ?, tea, ?), ?houses),
25
+ member(house(?, ?, snail, ?, old_gold), ?houses),
26
+ adjacent(house(?, ?, ?, ?, chesterfields), house(?, ?, fox, ?, ?), ?houses),
27
+ adjacent(house(?, ?, ?, ?, kools), house(?, ?, horse, ?, ?), ?houses),
28
+ member(house(?, ?, ?, orange_juice, lucky_strike), ?houses),
29
+ member(house(?, japanese, ?, ?, parliaments), ?houses),
30
+ member(house(?, ?waterdrinker, ?, water, ?), ?houses),
31
+ member(house(?, ?zebraowner, zebra, ?, ?), ?houses).
32
32
 
33
33
  % Positional and neighborhood helpers keep the clue encoding readable.
34
- first([?x|?_], ?x).
35
- third([?_, ?_, ?x|?_], ?x).
34
+ first([?x|?], ?x).
35
+ third([?, ?, ?x|?], ?x).
36
36
 
37
37
  adjacent(?a, ?b, ?list) :- next_to(?a, ?b, ?list).
38
38
  adjacent(?a, ?b, ?list) :- next_to(?b, ?a, ?list).
39
39
 
40
- next_to(?x, ?y, [?x, ?y|?_]).
41
- next_to(?x, ?y, [?_|?zs]) :- next_to(?x, ?y, ?zs).
40
+ next_to(?x, ?y, [?x, ?y|?]).
41
+ next_to(?x, ?y, [?|?zs]) :- next_to(?x, ?y, ?zs).
42
42
 
43
43
  waterDrinker(zebraPuzzle, ?waterdrinker) :- zebra(?waterdrinker, ?_zebraowner).
44
44
  zebraOwner(zebraPuzzle, ?zebraowner) :- zebra(?_waterdrinker, ?zebraowner).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eyelang",
3
- "version": "1.7.9",
3
+ "version": "1.7.11",
4
4
  "description": "A small Prolog-like logic programming language for rules, goals, answers, and proofs.",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/playground.html CHANGED
@@ -522,6 +522,7 @@
522
522
  "hamming-code",
523
523
  "hanoi",
524
524
  "heat-loss",
525
+ "herbrand-witnesses",
525
526
  "heron-theorem",
526
527
  "ideal-gas-law",
527
528
  "illegitimate-reasoning",
@@ -537,7 +538,9 @@
537
538
  "list-collection",
538
539
  "lldm",
539
540
  "manufacturing-quality-control",
541
+ "map-four-color-search",
540
542
  "matrix-chain-order",
543
+ "matrix-noncommutativity",
541
544
  "microgrid-dispatch",
542
545
  "missionaries-cannibals",
543
546
  "modal-logic-kripke",
@@ -554,21 +557,24 @@
554
557
  "orbital-transfer-design",
555
558
  "path-discovery",
556
559
  "peano-arithmetic",
560
+ "peano-calculus",
557
561
  "peasant",
558
562
  "pell-equation",
559
563
  "pendulum-period",
560
564
  "polynomial",
565
+ "prime-range",
561
566
  "proof-contrapositive",
562
567
  "quadratic-formula",
563
568
  "radioactive-decay",
564
569
  "reusable-builtins",
565
570
  "riemann-hypothesis",
571
+ "route-planning",
566
572
  "security-incident-correlation",
567
573
  "send-more-money",
568
574
  "service-impact",
575
+ "shoelace-polygon-area",
569
576
  "sieve",
570
577
  "skolem-functions",
571
- "herbrand-witnesses",
572
578
  "socket-age",
573
579
  "socket-family",
574
580
  "socrates",
@@ -577,6 +583,7 @@
577
583
  "stirling-bell-numbers",
578
584
  "sudoku-4x4",
579
585
  "superdense-coding",
586
+ "symbolic-derivative",
580
587
  "term-tools",
581
588
  "totient-summatory",
582
589
  "trust-flow-provenance-threshold",
@@ -587,6 +594,7 @@
587
594
  "weighted-interval-scheduling",
588
595
  "witch",
589
596
  "wolf-goat-cabbage",
597
+ "workplace-compliance",
590
598
  "zebra"
591
599
  ];
592
600
  const FALLBACK_SOURCE = `materialize(answer, 1).
@@ -861,9 +869,12 @@ answer(ok) :- eq(ok, ok).
861
869
  while (j < text.length && /[\d.]/.test(text[j])) j++;
862
870
  out += span('number', text.slice(i, j));
863
871
  i = j;
864
- } else if (ch === '?' && /[A-Za-z_]/.test(text[i + 1] || '')) {
865
- let j = i + 2;
866
- while (j < text.length && /[A-Za-z0-9_]/.test(text[j])) j++;
872
+ } else if (ch === '?') {
873
+ let j = i + 1;
874
+ if (/[A-Za-z_]/.test(text[j] || '')) {
875
+ j++;
876
+ while (j < text.length && /[A-Za-z0-9_]/.test(text[j])) j++;
877
+ }
867
878
  out += span('variable', text.slice(i, j));
868
879
  i = j;
869
880
  } else if (/[a-z]/.test(ch)) {
package/src/parser.js CHANGED
@@ -43,14 +43,14 @@ function isNameContinueCode(code) {
43
43
  function isQuestionVariableStart(source, pos) {
44
44
  if (source[pos] !== '?') return false;
45
45
  const code = (source[pos + 1] ?? '').charCodeAt(0);
46
- return code === 95 || isAsciiLetterCode(code);
46
+ return !source[pos + 1] || code === 95 || isAsciiLetterCode(code) || !isNameContinueCode(code);
47
47
  }
48
48
 
49
49
  function isPlainAtomStartCode(code) {
50
50
  return code >= 97 && code <= 122;
51
51
  }
52
52
 
53
- const graphicAtomChars = '#$&*+-/<=>?@^~\\';
53
+ const graphicAtomChars = '#$&*+-/<=>@^~\\';
54
54
 
55
55
  function isGraphicAtomCode(code) {
56
56
  return graphicAtomChars.includes(String.fromCharCode(code));
@@ -172,10 +172,9 @@ class Parser {
172
172
  if (isQuestionVariableStart(this.source, this.pos)) {
173
173
  const start = this.pos;
174
174
  this.take(); // ?
175
- this.take();
175
+ if (isNameContinueCode(this.peek().charCodeAt(0))) this.take();
176
176
  while (isNameContinueCode(this.peek().charCodeAt(0))) this.take();
177
- let text = this.source.slice(start, this.pos);
178
- if (text === '?_') text = `__anon${this.anonymous++}`;
177
+ const text = this.source.slice(start, this.pos);
179
178
  return { type: TOK.VAR, text, line };
180
179
  }
181
180
 
@@ -259,6 +258,7 @@ class Parser {
259
258
  if (this.token.type === TOK.VAR) {
260
259
  const name = this.token.text;
261
260
  this.advance();
261
+ if (name === '?') return variable(`__anon${this.anonymous++}`);
262
262
  return variable(name);
263
263
  }
264
264
  if (this.token.type === TOK.STRING) {
@@ -346,9 +346,9 @@ function isSimpleName(text) {
346
346
  const SIMPLE_NUMBER = /^-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?$/;
347
347
  const FAST_BINARY_FACT = /^([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\.$/;
348
348
  const FAST_BINARY_RULE = /^([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\s*:-\s*([a-z][A-Za-z0-9_]*)\(\s*([^,\s()[\]|"']+)\s*,\s*([^,\s()[\]|"']+)\s*\)\.$/;
349
- const SIMPLE_VARIABLE = /^\?[A-Za-z_][A-Za-z0-9_]*$/;
349
+ const SIMPLE_VARIABLE = /^\?(?:[A-Za-z_][A-Za-z0-9_]*)?$/;
350
350
  const SIMPLE_ATOM = /^[a-z][A-Za-z0-9_]*$/;
351
- const GRAPHIC_ATOM = /^[#$&*+\-\/<=>?@^~\\]+$/;
351
+ const GRAPHIC_ATOM = /^[#$&*+\-\/<=>@^~\\]+$/;
352
352
 
353
353
  function parseClausesFastNoSource(source) {
354
354
  source = String(source ?? '');
@@ -370,7 +370,7 @@ function parseClausesFastNoSource(source) {
370
370
  const scalarOrVariableFast = (text) => {
371
371
  if (!text || !isFastScalarToken(text)) throw new Error('bad simple term');
372
372
  const first = text.charCodeAt(0);
373
- if (text === '?_') return variable(`__anon${anonymous++}`);
373
+ if (text === '?') return variable(`__anon${anonymous++}`);
374
374
  if (SIMPLE_VARIABLE.test(text)) {
375
375
  const existing = variableCache.get(text);
376
376
  if (existing) return existing;
package/src/term.js CHANGED
@@ -136,7 +136,7 @@ export function termIsGround(term, env = new Env()) {
136
136
  return resolved.args.every((arg) => termIsGround(arg, env));
137
137
  }
138
138
 
139
- const graphicAtomChars = new Set('#$&*+-/<=>?@^~\\'.split(''));
139
+ const graphicAtomChars = new Set('#$&*+-/<=>@^~\\'.split(''));
140
140
 
141
141
  function isAbsoluteIriText(text) {
142
142
  return /^[A-Za-z][A-Za-z0-9+.-]*:[^\s<>"'{}|\\^`]*$/.test(text);
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(division_by_zero_fails) :- div(1, 0, ?_).
2
+ answer(division_by_zero_fails) :- div(1, 0, ?).
@@ -3,5 +3,5 @@ materialize(iri_subject, 1).
3
3
  materialize(iri_object, 1).
4
4
  triple(<https://example.org/alice>, <https://schema.org/name>, "Alice").
5
5
  triple(<urn:example:bob>, <https://schema.org/knows>, <https://example.org/alice>).
6
- iri_subject(?iri) :- triple(?iri, ?_, ?_).
7
- iri_object(?iri) :- triple(?_, <https://schema.org/knows>, ?iri).
6
+ iri_subject(?iri) :- triple(?iri, ?, ?).
7
+ iri_object(?iri) :- triple(?, <https://schema.org/knows>, ?iri).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(difference_end_before_start_fails) :- difference("2024-01-01", "2024-01-02", ?_).
2
+ answer(difference_end_before_start_fails) :- difference("2024-01-01", "2024-01-02", ?).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(difference_invalid_date_fails) :- difference("2024-02-30", "2024-02-01", ?_).
2
+ answer(difference_invalid_date_fails) :- difference("2024-02-30", "2024-02-01", ?).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(holds_ignores_string_parts) :- holds("not a term", ?_, ?_).
2
+ answer(holds_ignores_string_parts) :- holds("not a term", ?, ?).
@@ -1,5 +1,5 @@
1
1
  % Reference 5.3, 5.4: lists may contain structured terms that unify positionally.
2
2
  node([pair(a, b), pair(c, d)]).
3
- answer(first_key, ?x) :- node([pair(?x, ?_), pair(c, d)]).
3
+ answer(first_key, ?x) :- node([pair(?x, ?), pair(c, d)]).
4
4
  answer(second_key, ?x) :- node([pair(a, b), pair(?x, d)]).
5
5
  materialize(answer, 2).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(length_improper_fails) :- length([a | b], ?_).
2
+ answer(length_improper_fails) :- length([a | b], ?).
@@ -1,5 +1,5 @@
1
1
  % Reference 5.3, 6, 7.1: structured rule heads destructure matching goals.
2
2
  unpack(pair(?x, ?y), ?x, ?y).
3
- answer(first, ?a) :- unpack(pair(alpha, beta), ?a, ?_).
4
- answer(second, ?b) :- unpack(pair(alpha, beta), ?_, ?b).
3
+ answer(first, ?a) :- unpack(pair(alpha, beta), ?a, ?).
4
+ answer(second, ?b) :- unpack(pair(alpha, beta), ?, ?b).
5
5
  materialize(answer, 2).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(arg_atom_fails) :- arg(1, atom, ?_).
2
+ answer(arg_atom_fails) :- arg(1, atom, ?).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(arg_zero_fails) :- arg(0, pair(a, b), ?_).
2
+ answer(arg_zero_fails) :- arg(0, pair(a, b), ?).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(compound_name_arguments_bad_args_fails) :- compound_name_arguments(?_, pair, not_a_list).
2
+ answer(compound_name_arguments_bad_args_fails) :- compound_name_arguments(?, pair, not_a_list).
@@ -1,5 +1,5 @@
1
1
  % Reference 3.4, 5.1, 7.1: each anonymous variable occurrence is fresh.
2
2
  pair(a, one).
3
3
  pair(b, two).
4
- answer(fresh, yes) :- pair(a, ?_), pair(b, ?_).
4
+ answer(fresh, yes) :- pair(a, ?), pair(b, ?).
5
5
  materialize(answer, 2).
@@ -1,4 +1,4 @@
1
- % Reference 3.4, 5.1: `?_name` variables are named variables; only exactly `?_` is anonymous.
1
+ % Reference 3.4, 5.1: `?_name` variables are named variables; only exactly `?` is anonymous.
2
2
  pair(a, a).
3
3
  pair(a, b).
4
4
  answer(shared, ?_value) :- pair(?_value, ?_value).
@@ -1,4 +1,4 @@
1
- % Each ?_ occurrence is fresh, so these two goals do not have to agree.
1
+ % Each ? occurrence is fresh, so these two goals do not have to agree.
2
2
  materialize(answer, 1).
3
3
  pair(a, b).
4
- answer(ok) :- pair(?_, ?_).
4
+ answer(ok) :- pair(?, ?).
@@ -1,2 +1,2 @@
1
1
  materialize(answer, 1).
2
- answer(anonymous_not_reused) :- eq(pair(?_, ?_), pair(a, b)).
2
+ answer(anonymous_not_reused) :- eq(pair(?, ?), pair(a, b)).
@@ -1,6 +1,6 @@
1
- % Each `?_` occurrence is anonymous and independent.
1
+ % Each `?` occurrence is anonymous and independent.
2
2
  materialize(answer, 1).
3
3
  pair(a, b).
4
4
  pair(c, d).
5
- answer(left(?x)) :- pair(?x, ?_).
6
- answer(right(?y)) :- pair(?_, ?y).
5
+ answer(left(?x)) :- pair(?x, ?).
6
+ answer(right(?y)) :- pair(?, ?y).
@@ -1 +1 @@
1
- parse line 1: expected ), got 1
1
+ parse line 1: bad character "?"
@@ -1 +1 @@
1
- parse line 1: expected ), got 1
1
+ parse line 1: bad character "?"
@@ -639,9 +639,9 @@ function whiteBoxCases() {
639
639
  },
640
640
  },
641
641
  {
642
- name: 'parser treats question-mark underscore as anonymous',
642
+ name: 'parser treats bare question mark as anonymous',
643
643
  run: () => {
644
- const clauses = parseProgramText('p(?_, ?_).\n');
644
+ const clauses = parseProgramText('p(?, ?).\n');
645
645
  const left = clauses[0].head.args[0].name;
646
646
  const right = clauses[0].head.args[1].name;
647
647
  assertEqual(left.startsWith('__anon'), true, 'left anonymous');