There are several issues here, let's start first with the most obvious:
Modeling problems
You have a relation (result/2
is maybe not the best name), and this relation is supposed to model when decline
and when offer
should be true. Before reading your program, I prefer to ask Prolog:
?- result(X, decline), result(X, offer).
X in 11..20
; false.
So for the values from 11 up to 20, your relation is ambiguous. If you want to make a decision, then fix this relation first. Actually, I would start with
- a better name for the relation that makes clear it is a relation
- no imperative verbiage (like
Input
or imperatives)
- a more compact formulation, you don't need so many
(=)/2
goals in your program. Instead, you can write it like:
heigth_decision(I, decline) :-
I #< 10.
Answers and success vs. solutions in CLP
And then there is another problem which is more fundamental. This is actually much more serious, since all the SO-answers given so far ignore this aspect entirely. It is about the notion of answers and success and on the other hand the notion of solutions.
When you ask a query in Prolog - what you get back is an answer. Such an answer might contain solutions, like the answer L = [_,_]
which contains infinitely many solutions. Or an answer may contain exactly one solution like Decision = decline
. But there is much more in between if you are using constraints like library(clpfd)
.
You can now get finitely many solutions:
?- abs(X) #< 3.
X in -2..2.
Or infinitely many:
?- X #> Y.
Y#=<X+ -1.
But you can get also exactly one solution, which does not look like one:
?- 2^X #= 1.
2^X#=1.
So, just to restate this: We have here exactly one solution in the integers, but for Prolog this is way too complex. What we got back was an answer that states: Yes that is all true, provided all this fine print is true.
Worse, sometimes we get answers back that do not contain any solution.
?- X^X#=0.
X^X#=0.
If Prolog would be smart enough, it would answer false
. But it cannot be always that smart, simply because you can easily formulate undecidable problems. Such an answer is sometimes called inconsistency. The German notion Scheinlösung (~fake solution, but with less negative connotation) conveys the idea a bit better.
So an answer may contain solutions, but some answers do not contain solutions at all. For this reason, the success of a goal cannot be taken as the existence of a solution! That is, all SO-answers suggesting some kind of commit as (;)/2 – if-then-else, once/1, or !/0 are all incorrect, if they take the success as a solution. To see this, try them with:
?- X^X#=0, result(X,decline).
X in 11..sup, X^X#=0
; false.
?- X^X#=0, result(X,offer).
X in 0..20, X^X#=0.
So how can you now be sure of anything?
You can rely on the failure of a goal.
You can try labeling/2
, but this only works on finite domains.
You can use call_residue_vars/2
and copy_term/3
to determine if there are constraints "hanging around"
Unfortunately, you cannot entirely rely on SWI's toplevel which hides constraints that are unrelated to the variables in an answer. Only SICStus does display them correctly.
Input=15
, then the second goal should not be considered anymore" means that "all possible answers" should be just[decline]
, right? – GlyptodontResult=decline
ifInput in 11..sup
andResult=offer
ifInput in 0..10
– Finned