Backtracking & the Search Tree
prolog1-1 showed ; producing a second answer without explaining how. Here's the real machinery underneath — and a genuinely rich comparison to a mechanism Haskell only offers as one specific, opt-in monad.
The Search Tree — How Prolog Actually Finds Answers
When a goal has multiple clauses that could match, Prolog tries the first one. If that path later leads to failure, Prolog automatically backtracks to try the next alternative. A useful mental model: a tree of choices, explored via depth-first search, backing up and trying a different branch whenever the current one dead-ends.
Conjunction and the Order Goals Are Tried
Goals are tried left to right — and if a later goal fails, Prolog backtracks into an earlier goal to try its next alternative there, not just moving on independently. Genuinely sequential dependency, matching haskell2-3's own >>= chaining in spirit (each step can depend on what came before) — but Prolog explores every alternative automatically, with no explicit lambda written per step.
; for Explicit Alternatives (Disjunction)
; is logical OR, usable directly inside a rule body — not just something the top-level REPL shows between answers. Worth naming explicitly: the top-level's own ; prompt and rule-body ; are genuinely the same underlying mechanism, just triggered in two different places.
Comparison to Haskell's Own [] Monad
A genuinely rich comparison: haskell2-3's own list monad represents nondeterminism — >>= on [] explores every combination of possible results, conceptually similar in spirit to Prolog's backtracking search. But Prolog's version is baked into the entire language's execution model by default — every goal call is implicitly a potential source of backtracking, not something wrapped in one specific type a programmer opts into. The same distinction haskell1-5 drew between Java's opt-in Stream laziness and Haskell's own language-wide laziness, appearing again here in a new context: Haskell's [] monad is one specific tool; Prolog's backtracking is the language's own default way of running everything.
A Practical Example — Generating Combinations
Real, useful combinatorial work — no explicit nested loop was written anywhere. Backtracking generates every pairing automatically, on demand.
Backtracking Can Be Expensive — A Real, Honest Performance Note
Searching a large tree with many choice points can be genuinely slow if the search space isn't constrained somehow. Chapter 8's own ! (cut) is one real tool for controlling this — foreshadowed here without going deep into it yet.
| Aspect | Haskell [] monad (haskell2-3) | Prolog backtracking |
|---|---|---|
| Scope | one specific type, opted into | the language's own default execution model |
| Exploration | explicit >>= chains | automatic, on every goal call |
| Getting the "next" result | the list itself already holds all results | ; requests the next one on demand |
; disjunction — reach for ; specifically when the alternatives are genuinely local to one small piece of logic.
Coding Challenges
Write three color/1 facts and three size/1 facts, then run a single query combining color(X), size(Y) and use ; to retrieve all combinations.
📄 View solutionWrite a rule using an inline ; disjunction (e.g. drink(mary, X) :- X = wine ; X = beer.) and query it, retrieving both answers.
📄 View solutionWrite a short comment explaining the real difference in SCOPE between Prolog's own backtracking and Haskell's [] monad, using a concrete example of ordinary Prolog code (not wrapped in anything special) that is automatically backtracking-capable.
📄 View solutionChapter 4 Quick Reference
- Prolog explores a search tree depth-first, automatically backtracking to the next alternative on failure
- Goals in a conjunction are tried left to right, with backtracking able to reach back into an earlier goal — sequential dependency in spirit like haskell2-3's own >>=, but automatic
- ; is logical OR, usable directly in a rule body — the same mechanism as the top-level's own "next answer" prompt
- Prolog's backtracking is the language's own default execution model — a real scope difference from Haskell's own opt-in [] monad, echoing haskell1-5's Java-Streams-vs-language-wide-laziness distinction
- A large, unconstrained search space can be genuinely slow — "slow" and "never terminates" look identical while waiting
- Next chapter: lists — Prolog's own [H|T] syntax, a genuine visual convergence with Haskell's own (x:xs)