Prolog中“良构谓词(well behaved predicate)”的定义与相关疑问
Great question! Let's break this down clearly since SWI-Prolog's docs do throw around "well behaved predicate" without a formal glossary entry, and the choicepoint rule can be confusing at first.
You're right that there's no strict, formal definition in SWI-Prolog's terminology glossary—this is more of a community-established term for predicates that follow best practices and behave reliably as users expect. Here are the core traits that define one:
- Predictable behavior: For a given input mode (e.g.,
(+,?)), it acts exactly as intended. A deterministic predicate stays deterministic; a multi-solution predicate returns all expected results without surprises. - No unintended side effects: It doesn't modify the Prolog database, global state, or perform I/O unless that's explicitly part of its purpose (like predicates with
assertorwritein their names). - Minimal, purposeful choicepoints: It only keeps choicepoints when they're necessary to support backtracking for multiple solutions. Unnecessary choicepoints are cleaned up.
- Robust error handling: When given invalid inputs, it either fails gracefully or throws a clear, meaningful error (e.g., using
domain_error/2) instead of crashing or returning incorrect results.
SWI-Prolog's docs emphasize "no choicepoints for well behaved predicates" with an important context: this rule applies to predicates that aren't designed to return multiple solutions—i.e., deterministic and semi-deterministic ones. Let's break this down:
- Deterministic predicates: These are predicates that either succeed exactly once or fail. A well behaved deterministic predicate must not leave any choicepoints after success (or failure). Choicepoints here are redundant—they waste memory and can lead to unexpected backtracking later. For example,
memberchk/2(the deterministic sibling ofmember/2) uses an implicit cut to clean up choicepoints once it finds a match. - Semi-deterministic predicates: These are predicates that can succeed at most once (either once or not at all). Like deterministic predicates, a well behaved semi-deterministic predicate should not leave choicepoints after success. Tools like
once/1exist specifically to wrap predicates and enforce this—they run the predicate once, then clean up any remaining choicepoints. - Multi-solution predicates: This is the exception! Well behaved multi-solution predicates should leave choicepoints after each successful match. These choicepoints are intentional—they allow users to backtrack and retrieve all possible results, which is the core purpose of the predicate. For example,
member/2keeps choicepoints so you can iterate through all elements in a list via backtracking.
In short: The docs' advice isn't a blanket rule for all well behaved predicates—it's a guideline for predicates that aren't meant to produce multiple answers. For those, choicepoints are unnecessary and a sign of poor design. For multi-solution predicates, choicepoints are part of their intended functionality.
内容的提问来源于stack exchange,提问作者G_V

