Skip to content

Commit a0a616d

Browse files
author
Doug Ransom
committed
docs: add reification guideline preferring direct reified predicates over wrapping boolean assignments in if_/3
1 parent 78ae209 commit a0a616d

4 files changed

Lines changed: 21 additions & 2 deletions

File tree

.agents/AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ All Prolog code (regardless of target engine) MUST follow the universal style an
3535
- Prefer pure efficiency: first-argument indexing, reified `zcompare/3` arithmetic comparison, and early constraint pruning (`dif/2`, [`CLP(Z)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/clpz.pl)).
3636
- Prefer coroutining (`freeze/2`, `when/2`) to suspend goals until variables are instantiated, preferring [`CLP(Z)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/clpz.pl)/`dif/2` over manual coroutining where specialized constraints apply.
3737
- When relating conditions to values, isolate the test-value relation (e.g. `if_(G, A="A", A="B"), write(A)`).
38+
- **Direct Reification over `if_/3` for Booleans**: Always prefer direct reified predicates (e.g. `=(X, Y, Truth)`, `memberd_t/3`, `tpartition/4`) over wrapping boolean assignments inside `if_/3` (e.g. use `=(X, Y, Truth)` instead of `if_(X = Y, Truth = true, Truth = false)`). Reserve `if_/3` strictly for selecting non-boolean values (`if_(G, Val = 'yes', Val = 'no')`) or executing conditional branches with distinct control paths.
3839
- **Declarative AI Workflow**: [.agents/skills/prolog-declarative-workflow/SKILL.md](.agents/skills/prolog-declarative-workflow/SKILL.md)
3940
- Use declarative reasoning based on unification, constraints, and backtracking (never imperative thinking).
4041
- Specify mode (`+`/`-`), determinism (`det`, `semidet`, `nondet`), and choice-point expectations.

.agents/references/prolog_guidelines.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,24 @@ print_status(X) :-
4848
write(Status).
4949
```
5050

51+
### Prefer Direct Reified Predicates over Wrapping Booleans in `if_/3`
52+
53+
When working with `library(reif)`, always prefer direct reified predicates over wrapping boolean assignments inside `if_/3`:
54+
55+
- **Use Reified Equality (`=(X, Y, Truth)`)**: Use `=(X, Y, Truth)` (or `X = Y`) directly instead of `if_(X = Y, Truth = true, Truth = false)`.
56+
- **Use Reified Predicates Directly**: Use reified predicates (e.g. `=/3`, `memberd_t/3`, `tpartition/4`) directly whenever a variable is being bound to boolean `true`/`false` based on a test.
57+
- **Reserve `if_/3` for Non-Boolean Values & Control Flow**: Reserve `if_/3` strictly for selecting non-boolean values (`if_(G, Val = 'yes', Val = 'no')`) or executing conditional branches with different control paths.
58+
59+
```prolog
60+
% BAD: Wrapping boolean assignment inside if_/3
61+
is_zero_bool(X, Truth) :-
62+
if_(X = 0, Truth = true, Truth = false).
63+
64+
% GOOD: Use reified equality predicate directly
65+
is_zero_bool(X, Truth) :-
66+
=(X, 0, Truth).
67+
```
68+
5169
### Higher-Order Programming & Partial Goals (`call/N`, `call//N`, `library(lambda)`)
5270

5371
Prefer higher-order predicates and closures over primitive recursive list traversals or duplicating predicate clauses:

.agents/skills/prolog-code-review/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Use this skill when reviewing Prolog pull requests, auditing code diffs, or eval
1111

1212
| Dimension | Check Items |
1313
| :--- | :--- |
14-
| **Logical Purity** | - Are cuts (`!`), negation-as-failure (`\+/1`), and soft cuts (`->`) avoided in favor of `if_/3` from `library(reif)` or `dif/2` (preferring `dif(X, Y)` over `\+ (X = Y)`)?<br>- Are cuts (`!`), `\+/1`, `->` omitted for performance tuning? If introduced for *correctness*, is an explicit inline comment present justifying why pure logic constructs (`if_/3`, `dif/2`) were insufficient?<br>- Are conditions and test-values isolated (e.g. `if_(G, A="A", A="B"), write(A)`)?<br>- Are Definite Clause Grammars (`-->`) used for sequence parsing/formatting instead of imperative loops? |
14+
| **Logical Purity** | - Are cuts (`!`), negation-as-failure (`\+/1`), and soft cuts (`->`) avoided in favor of `if_/3` from `library(reif)` or `dif/2` (preferring `dif(X, Y)` over `\+ (X = Y)`)?<br>- Are cuts (`!`), `\+/1`, `->` omitted for performance tuning? If introduced for *correctness*, is an explicit inline comment present justifying why pure logic constructs (`if_/3`, `dif/2`) were insufficient?<br>- Are conditions and test-values isolated (e.g. `if_(G, A="A", A="B"), write(A)`)?<br>- Are direct reified predicates (e.g., `=(X, Y, Truth)`, `memberd_t/3`) used directly when binding booleans instead of wrapping boolean assignments inside `if_/3`?<br>- Are Definite Clause Grammars (`-->`) used for sequence parsing/formatting instead of imperative loops? |
1515
| **Clean Data Representation** | - Can every data element kind be distinguished solely by its **principal functor** (e.g., `leaf(L)` vs `node(L, R)`)?<br>- Are defaulty representations avoided so argument indexing works automatically?<br>- Are external defaulty/unstructured inputs converted into clean trees early? |
1616
| **Determinism & Performance** | - Do deterministic predicates leave open choice points?<br>- Is the primary input placed in the first argument position for first-argument indexing?<br>- Is `zcompare/3` used for reified integer comparisons?<br>- Are recursive calls in tail position (TCO) with accumulators? |
1717
| **Human Editing Syntax** | - Are neck operators `:-` free of dropped characters (`:` instead of `:-`)?<br>- Are line comments formatted with `%` rather than `#` or `//`?<br>- Are DCG rules declared with `-->` rather than `->`?<br>- Are comparison operators Prolog-standard (`=\=`, `\=`, `=<`, `>=`) rather than C/Python symbols (`!=`, `<=`, `=>`)?<br>- Do module export lists (`:- module/2`), import lists (`:- use_module/2`), and doc comments use ISO `Name//Arity` indicator notation for DCG non-terminals? |

.agents/skills/scryer-prolog-standards/SKILL.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Scryer Prolog guidelines emphasize pure Prolog conventions and standard ISO-comp
2323
| :--- | :--- | :--- | :--- |
2424
| **DCG Parsing** | `:- use_module(`[`library(dcgs)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/dcgs.pl)`).` | `phrase/2`, `phrase/3`, `seq//1`, `seq_with//2` | Mandatory for any `-->` grammars. |
2525
| **Character I/O** | `:- use_module(`[`library(charsio)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/charsio.pl)`).` | `read_from_chars/2`, `write_to_chars/2`, `get_single_char/1` | All strings in Scryer are `chars`. |
26-
| **Reified Logic** | `:- use_module(`[`library(reif)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/reif.pl)`).` | `if_/3`, `dif/2`, `(=)/3`, `memberd_t/3`, `tfilter/3` | Pure reified conditional testing. |
26+
| **Reified Logic** | `:- use_module(`[`library(reif)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/reif.pl)`).` | `if_/3`, `dif/2`, `(=)/3`, `memberd_t/3`, `tfilter/3` | Pure reified conditional testing. Prefer direct reified predicates (`=/3`, `memberd_t/3`) over wrapping boolean assignments in `if_/3`. |
2727
| **CLP(Z) Constraints**| `:- use_module(`[`library(clpz)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/clpz.pl)`).` | `(#=)/2`, `(#\/)/2`, `label/1`, `labeling/2`, `zcompare/3` | Integer arithmetic constraints (Scryer uses `clpz`, NOT `clpfd`). |
2828
| **Safe Type Testing**| `:- use_module(`[`library(si)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/si.pl)`).` | `list_si/1`, `atom_si/1`, `integer_si/1`, `chars_si/1` | Monotonic type tests (`si` = safely instantiated). |
2929
| **Higher-Order Lambda**| `:- use_module(`[`library(lambda)`](https://github.com/mthom/scryer-prolog/blob/master/src/lib/lambda.pl)`).` | `\X^...`, `\X^Y^Goal` | Inline anonymous lambda expressions. |

0 commit comments

Comments
 (0)