Challenge 3: Why solve(X is 1 + 1) Fails, and How to Fix It — Possible Solution ==================================================================== -- Why does solve(X is 1 + 1) fail? -- -- -- X is 1 + 1 matches none of solve/1's first four specialized -- clauses (it isn't true, a conjunction, a disjunction, or a -- negation), so it falls through to the generic final clause: -- solve(A) :- clause(A, Body), solve(Body). This tries -- clause(X is 1 + 1, Body) -- looking up a USER-DEFINED clause whose -- head matches is/2. But is/2 is a built-in predicate, implemented -- directly by the Prolog engine itself, not defined via ordinary -- clauses the way parent/2 or grandparent/2 are. clause/2 can only -- see clauses that actually exist in the loaded program's database, -- and no such clause exists for is/2 -- so clause(X is 1 + 1, Body) -- fails immediately, and solve/1 fails right along with it, without -- ever performing the addition. -- A fix: special-case built-ins before the generic fallback -- solve(true) :- !. solve((A, B)) :- !, solve(A), solve(B). solve(G) :- predicate_property(G, built_in), !, call(G). solve(A) :- clause(A, Body), solve(Body). ?- solve(X is 1 + 1). X = 2. -- Explanation of the fix -- -- -- The new third clause checks predicate_property(G, built_in) -- -- true for predicates like is/2 that the Prolog engine itself -- implements, rather than something clause/2 could ever look up. -- When that check succeeds, the clause cuts and simply calls G -- directly via Prolog's own call/1, handing the goal straight to the -- real engine instead of trying to reinterpret it through clause/2. -- This has to be placed BEFORE the generic clause/2-based fallback, -- so built-ins are recognized and handled before solve/1 ever -- attempts (and fails) the clause/2 lookup that doesn't apply to -- them. WHY THIS WORKS AS AN ANSWER ------------------------------ This traces the exact failure back to clause/2 having no entries for a built-in predicate, then supplies a genuinely working fix using predicate_property/2 and call/1, placed correctly ahead of the generic fallback clause, directly resolving the chapter's own warn-box gap.