I'm trying to understand how Prolog works. I'm using SWI-Prolog. Here's a bit of code:
forall(C1,C2) :- \+ (C1, \+ C2).
foo(N) :- N < 10.
bar(N) :- N > 5.
foobar(N) :- forall(foo(N),bar(N)).
It produces desired output if I do something like:
?- foobar(5).
false.
But when I try to see all the possible values I get an error:
?- foobar(N).
ERROR: </2: Arguments are not sufficiently instantiated
What is going on here?
Basically you are writing a program the check for a global implication:
forall N, if N < 10 then N > 5
and you want to know for which domain of N
that holds.
Now you correctly rewrite that in prolog as:
\+ ( N < 10, \+ ( N > 5 ) ).
But if you try to give that query to the prolog interpreter, it will output the error:
?- \+ ( N < 10, \+ ( N > 5 ) ).
ERROR: </2: Arguments are not sufficiently instantiated
because the arguments of <
are not instantiated. It happens the same thing with a simple query such as N < 3
. Of course, if you instantiate it before the query, the problem goes away:
?- N=5, \+ ( N < 10, \+ ( N > 5 ) ).
false.
(the statement does not hold for N=5)
?- N=6, \+ ( N < 10, \+ ( N > 5 ) ).
N = 6.
(but it holds for N=6).
You could also put a predicate that generates multiple assignments for N
via backtracking, in place of that N=6
:
?- between(1, 12, N), \+ ( N < 10, \+ ( N > 5 ) ).
N = 6 ;
N = 7 ;
N = 8 ;
N = 9 ;
N = 10 ;
N = 11 ;
N = 12.
but for a large domain, that is going to be highly inefficient (it will require backtracking for every element of the domain).
If you want to reason about finite domains (i.e. integers), you can use the CLPFD library as @lurker suggested. This approach is more efficient, because it has rules for reasoning about intervals, intersection on intervals, and many more.
You have to replace <
, >
, ,
, \+
with the CLP operators #<
, #>
, #/\
, #\
. Let's try it:
?- use_module(library(clpfd)).
?- #\ ( N #< 10 #/\ #\ ( N #> 5 ) ).
N+1#=_G11193,
N#>=6#<==>_G11205,
10#>=_G11193#<==>_G11217,
_G11217 in 0..1,
_G11217#/\_G11244#<==>0,
_G11244 in 0..1,
#\_G11205#<==>_G11244,
_G11205 in 0..1.
that might be a bit hard to read, but among many other things, it is telling you the answer you are looking for, that is the domain of N: N #>= 6
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With