6

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?

repeat
  • 18,496
  • 4
  • 54
  • 166
akalikin
  • 1,071
  • 12
  • 35
  • 4
    The `2` and `>/2` operators require that all arguments have specific values (are instantiated) in order to work. So if `N` doesn't have a value (is not *instantiated*) then `N < 10` will generate that error. If you're trying to generate possible values with certain constraints, you might want to use the CLPFD library, then you can use `N #< 10`, etc. – lurker Mar 18 '15 at 19:07
  • @lurker Ok I see. How would I change the code so that it does output all possible integers? And not just checks if the argument satisfies the condition? Is it even possible? – akalikin Mar 18 '15 at 19:10
  • 1
    What do you intend to mean by it? – false Mar 18 '15 at 19:16
  • 1
    @mat: Before going against instantiation errors that effectively do not claim anything wrong, what about going against programs that produce incorrect answers first? – false Jul 26 '15 at 22:12
  • @mat: Why a 150 bounty: 100 or 200 have a better payoff – false Jul 26 '15 at 22:13
  • 1
    @false: In my view, there are way too many questions of this type on this site, and most of them can be trivially solved by simply using more declarative predicates. I want to reward users who propagate more elegant methods, typically giving more correct *and also* more general solutions. 150 points is a first sign of appreciation to encourage this. I give 200 points and more for more significant contributions, such as very elegant solutions. – mat Jul 27 '15 at 11:12
  • [3 bounties](http://stackoverflow.com/users/1613573/mat?tab=bounties&sort=offered) so far ... – false Jul 27 '15 at 11:39
  • 1
    And apparently having to justify the 3rd already. It's not at all fun to give bounties this way. – mat Jul 27 '15 at 11:42

2 Answers2

3

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.

fferri
  • 18,285
  • 5
  • 46
  • 95
2

TL;DR. Prolog has nice algebraic properties as long as you stick to its logically-pure core.


For details, read the following excellent answers to Prolog questions on StackOverflow:

Community
  • 1
  • 1
repeat
  • 18,496
  • 4
  • 54
  • 166