Hard cut (!) versus soft-cut (*->) for pruning a recursive search: which preserves debuggability?
0 reputation · 16 Jul 2020, 14:23 UTC
0 reputation · 16 Jul 2020, 14:23 UTC
I am writing a recursive predicate in SWI-Prolog that searches a large fact base and should commit to the first matching branch once a condition succeeds. Two documented mechanisms seem applicable: the classic cut operator !, which prunes all remaining choice points for the clause, and the soft-cut construct Condition *-> Then ; Else, which commits only to the Then branch if the condition succeeds once.
The constraint is maintainability: the predicate will be extended by other contributors, and I have read that red cuts can silently change a predicate's declarative meaning and break logical symmetry, while soft-cuts are described as preserving more transparent if-then-else semantics. However, I am unsure how each behaves when the committed goal itself contains nested disjunctions and further recursion, and whether the performance difference is meaningful in practice.
Assume SWI-Prolog 9.x, though notes on dialect differences are welcome since the code may later be ported.
! after the guard, or are they equivalent here?For a recursive search that must commit to the first successful branch, a soft‑cut (Condition *-> Then ; Else) is semantically safer than a hard cut (!) placed after the guard. The two are equivalent only when the guard is deterministic (has at most one solution) and the Then branch contains no backtracking points of its own.
Then branch only after the guard succeeds once; it leaves the guard’s alternative solutions alive and allows backtracking into the Else branch if the Then branch later fails. This preserves clearer if‑then‑else semantics and makes debugging easier because the programmer can see why a particular branch was chosen.Then branch, it prunes not only the guard’s choice points but also any choice points created inside the Then branch (e.g., nested disjunctions or further recursion) unless an explicit cut appears later inside that branch.Then branch. Those remain available for backtracking unless the programmer inserts another cut (hard or soft) within the branch itself.The soft‑cut introduces a modest overhead: the guard is evaluated, and a temporary choice point for the Else branch may be created. In SWI‑Prolog 9.x this overhead is typically small—often only a few percent—and only becomes measurable in tight loops where the guard succeeds the vast majority of the time. Profiling with statistics/2 or time/1 on a realistic data set is the only way to decide whether the cost justifies a hard cut.
! after the guard, another with Condition *-> Then ; Else.trace/0) and observe which choice points are pruned.statistics/2,time/1 to measure execution time on a large dataset.Else branch when the Then branch fails.To give a definitive recommendation, I need to know whether the guard predicate can succeed more than once for a given input. If the guard is guaranteed to be deterministic, a hard cut after it is safe and may avoid the tiny soft‑cut overhead; otherwise, the soft‑cut remains the safer choice.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.