Cut (!) — Controlling Backtracking, Honestly

Course 1 · Ch 8
Cut (!) — Controlling Backtracking, Honestly
A genuinely controversial feature, treated the way this course treats every real tradeoff — plainly

Fundamentals closes with Prolog's most debated single character. Cut is real, useful, and genuinely controversial within the Prolog community itself — this chapter doesn't pick a side, it explains exactly what's actually being traded.

What Cut Actually Does

!, when reached during execution, commits to every choice made so far in the current clause — permanently pruning any remaining backtracking alternatives, both for goals earlier in the same clause and for the choice of which other clause to try for the predicate itself.

A Concrete Example — Cutting Off Alternatives

max(X, Y, X) :- X >= Y, !. max(X, Y, Y). ?- max(3, 5, Result). Result = 5. ?- max(3, 5, Result), Result == 3. -- without the cut, backtracking could try clause 1 anyway and produce a WRONG "solution"

Without the cut, asking for further solutions via ; after the correct answer could backtrack into the first clause despite 3 >= 5 already having failed for those bindings in one call, or produce unintended additional results in more complex predicates. The cut commits: once X >= Y succeeds, this is the answer — no exploring further.

Green Cuts vs. Red Cuts — An Honest Distinction

A real, well-known distinction worth naming explicitly. A green cut only improves efficiency — it prunes alternatives that would have failed anyway, changing nothing about the program's actual logical meaning. A red cut genuinely changes the set of solutions a predicate produces compared to removing it. Red cuts are the controversial ones — a predicate relying on one can no longer be read as pure logic alone; understanding which kind you've written requires understanding your own program's behavior with and without the cut present.

The Real Cost to Declarative Purity

Stated plainly, matching this whole course's own established pattern (the same honesty haskell2-6 applied to monad transformer stacks): a predicate using cut can no longer be freely reordered, and its logical reading now depends on Prolog's own specific left-to-right, depth-first execution order. A real, genuine departure from pure declarative logic, where a set of facts and rules should mean the same thing regardless of execution strategy. Cut ties correctness to execution order — a real, controversial tradeoff, not a free efficiency win.

Cut in Rule Bodies — A Common, Practical Pattern

classify(X, negative) :- X < 0, !. classify(X, zero) :- X =:= 0, !. classify(X, positive).

The "if-then-else"-shaped idiom — genuinely practical, very common real-world Prolog code, not just a toy example. Each cut commits to that branch once its own condition succeeds, preventing later clauses from ever being tried for that same call.

Negation as Failure, Previewed

\+ Goal :- Goal, !, fail. \+ Goal.

A brief, honest forward-pointer: Course 2's own \+ (negation as failure) is commonly implemented internally using exactly this cut-based pattern — worth naming now, without going deep, since Course 2 covers \+ properly.

ApproachLogical meaningEfficiency
No cutfull, pure logical readingmay explore unnecessary alternatives
Green cutunchanged — same solutions either wayimproved — genuinely free win
Red cutgenuinely changed — a real tradeoffimproved, but at a real cost to purity
Ask: would removing this cut change WHICH solutions come back, not just how many alternatives get tried?
That question is the real test for green vs. red — if the answer is "the solutions themselves would differ," you've written a red cut, and it's worth knowing that consciously rather than by accident.
A cut's scope is the enclosing clause only
! does not reach back and prune choice points created by goals in a caller's own body, before the current clause was even entered — its reach stops at the clause it's written in. A real, genuine source of confusion about how "far" a given cut actually extends.

Coding Challenges

Challenge 1

Write the max/3 predicate exactly as shown in the chapter, query it for max(3, 5, Result), and press ; to confirm the cut prevents any second, incorrect answer from appearing.

📄 View solution
Challenge 2

Write the classify/2 predicate from the chapter, query it for a negative, a zero, and a positive number, and explain in a comment whether each cut used is a green cut or a red cut.

📄 View solution
Challenge 3

Write a short comment explaining, with a concrete example, why a predicate relying on a red cut can no longer be reordered freely the way pure Prolog facts/rules normally could be.

📄 View solution

Chapter 8 Quick Reference — Course 1 Complete

  • ! commits to every choice made so far in the current clause, pruning remaining alternatives for both earlier goals and other clauses
  • A green cut only improves efficiency — same solutions either way; a red cut genuinely changes which solutions come back
  • Cut ties a predicate's correctness to Prolog's own specific execution order — a real, honest departure from pure declarative logic
  • The if-then-else cut pattern (classify/2) is genuinely common, practical real-world Prolog
  • Course 2's own \+ (negation as failure) is commonly implemented internally using this exact cut-based pattern
  • A cut's scope stops at its own enclosing clause — it never reaches back into a caller's own choice points
  • Prolog Fundamentals is now complete. Course 2 (Intermediate/Advanced) begins with findall/bagof/setof — collecting backtracking's multiple solutions into a single concrete list.