Prolog unification broken when argument order is changed - prolog

I can’t seem to wrap my head around this. Consider the following dummy predicate:
foo(X, a) :- X < 10.
foo(X, b) :- X > 20.
When consulting:
?- foo(1, a).
true;
false.
I am not sure I completely understand how the choice point is created anyway (Perhaps because the two possible foo predicates are in a kind of or relationship and Prolog just tries to unify with both? Based on this line in the trace: Redo: (24) test:foo(8, a) and the subsequent fail, I suppose this is the case), but what really confuses me is why it works when the argument order is changed:
foo(a, X) :- X < 10.
foo(b, X) :- X > 20.
?- foo(a, 1).
true.
No choice point. What am I missing here?

TL;DR: read the documentation of the Prolog you are using. Pay attention to "clause indexing" or something of the kind.
You are missing that whichever Prolog implementation you are using is just clever enough to do indexing on the first argument in your second example. So when you pose the query ?- foo(a, Something). it never considers the other clause.
But this is really a matter of Prolog implementation, and not a matter of Prolog as a language. Maybe there are Prologs that can also avoid the choice point in the first example. Or maybe it provides a different mechanism to achieve the same. For example SWI-Prolog (among other Prologs) has something called "tabling". With it, you can do it like this:
:- table foo/2.
foo(X, a) :- X < 10.
foo(X, b) :- X > 20.
bar(a, X) :- X < 10.
bar(b, X) :- X > 20.
Now neither foo/2 nor bar/2 has the unexpected choice point:
?- foo(1, a).
true.
?- bar(a, 1).
true.

Related

Is it possible to write an inconsistent Prolog program using only pure Prolog, cut and `false`?

This one tickled my interest in theory:
Is it possible to write an inconsistent Prolog program, i.e. a program that answers both false and true depending on how it is queried, using only pure Prolog, the cut, and false?
For example, one could query p(1) and the Prolog Processor would says false. But when one queries p(X) the Prolog Processor would give the set of answers 1, 2, 3.
This can be easily achieved with "computational state examination predicates" like var/1 (really better called fresh/1) + el cut:
p(X) :- nonvar(X),!,member(X,[2,3]).
p(X) :- member(X,[1,2,3]).
Then
?- p(1).
false.
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
"Ouch time" ensues if this is high-assurance software. Naturally, any imperative program has no problem going off the rails like this on every other line.
So. can be done without those "computational state examination predicates"?
P.S.
The above illustrates that all the predicates of Prolog are really carrying a threaded hidden argument of the "computational state":
p(X,StateIn,StateOut).
which can be used to explain the behavour of var/1 and friends. The Prolog program is then "pure" when it only calls predicates that neither consult not modify that State. Well, at least that seems to be a good way to look at what is going on. I think.
Here's a very simple one:
f(X,X) :- !, false.
f(0,1).
Then:
| ?- f(0,1).
yes
| ?- f(X,1).
no
| ?- f(0,Y).
no
So Prolog claims there are no solutions to the queries with variables, although f(0,1) is true and would be a solution to both.
Here is one attempt. The basic idea is that X is a variable iff it can be unified with both a and b. But of course we can't write this as X = a, X = b. So we need a "unifiable" test that succeeds without binding variables like =/2 does.
First, we need to define negation ourselves, since it's impure:
my_not(Goal) :-
call(Goal),
!,
false.
my_not(_Goal).
This is only acceptable if your notion of pure Prolog includes call/1. Let's say that it does :-)
Now we can check for unifiability by using =/2 and the "not not" pattern to preserve success while undoing bindings:
unifiable(X, Y) :-
my_not(my_not(X = Y)).
Now we have the tools to define var/nonvar checks:
my_var(X) :-
unifiable(X, a),
unifiable(X, b).
my_nonvar(X) :-
not(my_var(X)).
Let's check this:
?- my_var(X).
true.
?- my_var(1).
false.
?- my_var(a).
false.
?- my_var(f(X)).
false.
?- my_nonvar(X).
false.
?- my_nonvar(1).
true.
?- my_nonvar(a).
true.
?- my_nonvar(f(X)).
true.
The rest is just your definition:
p(X) :-
my_nonvar(X),
!,
member(X, [2, 3]).
p(X) :-
member(X, [1, 2, 3]).
Which gives:
?- p(X).
X = 1 ;
X = 2 ;
X = 3.
?- p(1).
false.
Edit: The use of call/1 is not essential, and it's interesting to write out the solution without it:
not_unifiable(X, Y) :-
X = Y,
!,
false.
not_unifiable(_X, _Y).
unifiable(X, Y) :-
not_unifiable(X, Y),
!,
false.
unifiable(_X, _Y).
Look at those second clauses of each of these predicates. They are the same! Reading these clauses declaratively, any two terms are not unifiable, but also any two terms are unifiable! Of course you cannot read these clauses declaratively because of the cut. But I find this especially striking as an illustration of how catastrophically impure the cut is.

Prolog addition on wrapped values

I wrote a test program with bindings (facts) between atoms and numbers.
bind(a, 3).
bind(b, 4).
bind(c, 5).
As part of a toy interpreter, I want to be able to perform additions on these atoms using Prolog's native arithmetic operators. For instance, I want to be able to run this query:
% val(X) is the value bound to X
?- X is val(a) + val(b).
X = 7.
However, I'm struggling to find a way to allow this addition. My first approach would have been this one:
% val(X, Y): Y is the value bound to X
val(X, Y) :- bind(X, Y).
% Make val an arithmetic function
:- arithmetic_function(val/1).
However, arithmetic_function/1 is no longer part of Prolog (or at least SWI-Prolog says it's deprecated), so I can't use it. Then I believed the best solution would be to overload the + operator to take this into account:
% val(X, Y): Y is the value bound to X
val(val(X), Y) :- bind(X, Y).
% Overload the + operator
+(val(_X, XVal), val(_Y, YVal)) :- XVal + YVal.
But here I've got my syntax all messed up because I don't really know how to overload a native arithmetic operation. When I type in the sample query from before, SWI-Prolog says ERROR: Arithmetic: ``val(a)' is not a function.
Would you have hints about a possible solution or a better approach or something I missed?
From the docs, I tought you should use function_expansion/3.
But I'm unable to get it to work, instead, goal_expansion could do, but isn't very attractive... for instance, if you save the following definitions in a file bind.pl (just to say)
:- module(bind, [test/0]).
:- dynamic bind/2.
bind(a, 3).
bind(b, 4).
bind(c, 5).
% :- multifile user:goal_expansion/2.
user:goal_expansion(val(X), Y) :- bind(X, Y).
user:goal_expansion(X is Y, X is Z) :- expand_goal(Y, Z).
user:goal_expansion(X + Y, U + V) :- expand_goal(X, U), expand_goal(Y, V).
test :-
X is val(a) + val(b), writeln(X).
and consult it, you can run your test:
?- test.
7
edit
after Paulo suggestion, here is an enhanced solution, that should work for every binary expression.
user:goal_expansion(X is Y, X is Z) :- expr_bind(Y, Z).
expr_bind(val(A), V) :- !, bind(A, V).
expr_bind(X, Y) :-
X =.. [F, L, R], % get operator F and Left,Right expressions
expr_bind(L, S), % bind Left expression
expr_bind(R, T), % bind Right expression
Y =.. [F, S, T]. % pack bound expressions back with same operator
expr_bind(X, X). % oops, I forgot... this clause allows numbers and variables
having defined user as target module for goal_expansion, it works on the CLI:
?- R is val(a)*val(b)-val(c).
R = 7.
edit
now, let's generalize to some other arithmetic operators, using the same skeleton expr_bind uses for binary expressions:
user:goal_expansion(X, Y) :-
X =.. [F,L,R], memberchk(F, [is, =<, <, =:=, >, >=]),
expr_bind(L, S),
expr_bind(R, T),
Y =.. [F, S, T].
and unary operators (I cannot recall no one apart minus, so I show a simpler way than (=..)/2):
...
expr_bind(-X, -Y) :- expr_bind(X, Y).
expr_bind(X, X).
Now we get
?- -val(a)*2 < val(b)-val(c).
true.
One way to do it is using Logtalk parametric objects (Logtalk runs on SWI-Prolog and 11 other Prolog systems; this makes this solution highly portable). The idea is to define each arithmetic operation as a parametric object that understands an eval/1 message. First we define a protocol that will be implemented by the objects representing the arithmetic operations:
:- protocol(eval).
:- public(eval/1).
:- end_protocol.
The basic parametric object understands val/1 and contains the bind/2 table:
:- object(val(_X_), implements(eval)).
eval(X) :-
bind(_X_, X).
bind(a, 3).
bind(b, 4).
bind(c, 5).
:- end_object.
I exemplify here only the implementation for arithmetic addition:
:- object(_X_ + _Y_, implements(eval)).
eval(Result) :-
_X_::eval(X), _Y_::eval(Y),
Result is X + Y.
:- end_object.
Sample call (assuming the entities above are saved in an eval.lgt file):
% swilgt
...
?- {eval}.
% [ /Users/pmoura/Desktop/eval.lgt loaded ]
% (0 warnings)
true.
?- (val(a) + val(b))::eval(R).
R = 7.
This can be an interesting solution if you plan to implement more functionality other than expression evaluation. E.g. a similar solution but for symbolic differentiation of arithmetic expressions can be found at:
https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/symdiff
This solution will also work in the case of runtime generated expressions (term-expansion based solutions usually only work at source file compile time and at the top-level).
If you're only interested in expression evaluation, Capelli's solution is more compact and retains is/2 for evaluation. It can also be made more portable if necessary using Logtalk's portable term-expansion mechanism (but note the caveat in the previous paragraph).
This is perhaps not exactly what I was looking for, but I had an idea:
compute(val(X) + val(Y), Out) :-
bind(X, XVal),
bind(Y, YVal),
Out is XVal + YVal.
Now I can run the following query:
?- compute(val(a) + val(c), Out).
Out = 8.
Now I need to define compute for every arithmetic operation I'm interested in, then get my interpreter to run expressions through it.

Prolog - Backtracking through a set of dynamic options

I'm trying to trigger backtracking on a goal but in a dynamic way, if it's possible. To better exemplify my issue let's say we have the following PROLOG code:
num(1).
num(2).
num(3).
num(4).
num(5).
Then I head to SWI-Prolog and call: num(X). This triggers backtracking looking for all solutions, by typing ; .
What I would like is to remove those facts (num(1),num(2), etc) and replace that code with something thata generates those facts dynamically. Is there any way in which I can achieve this? Someting of the sorts,maybe?
num(X):- for X in 1..5
that yields the same solutions as the code above?
As far as I know, the findall predicate returns a list, which is not what I'm looking for. I would like to backtrack through all answers and look through them using ; in the console.
Yes there is, and you were already very close!
:- use_module(library(clpfd)).
num(X) :-
X in 1..5.
?- num(X).
X in 1..5.
?- num(X), X #>3.
X in 4..5.
?- num(X), labeling([], [X]).
X = 1
; X = 2
; X = 3
; X = 4
; X = 5.
SWI-Prolog has the (non-ISO) predicate between/3 for that:
num(X) :- between(1, 5, X).
You can implement the predicate (for other Prologs and for further tweaking) like this:
between2(A, A, A) :- !. % green cut
between2(A, B, A) :- A < B.
between2(A, B, C) :-
A < B,
A1 is A + 1,
between2(A1, B, C).
The signature for both between/3 and between2/3 is (+From,+To,?X). It means that the From and To must be bound and X can be either bound or not. Also note that From and To must be integers such that From <= To. (Oh, and these integers must be written using Arabic numerals with an optional plus or minus sign before. And using ASCII. Is something non-obvious still missed? And the integers must not be too large or too small, although SWI-Prolog is usually compiled with unbounded integer support, so both between(1, 100000000000000000000000000000000000000000000, X) and between2(1, 100000000000000000000000000000000000000000000, X) usually work.)

Prolog program returns false

I implemented the following power program in Prolog:
puissance(_,0,1).
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
The code does what is supposed to do, but after the right answer it prints "false.". I don't understand why. I am using swi-prolog.
Can do like this instead:
puissance(X,N,P) :-
( N > 0 ->
A is N-1,
puissance(X,A,Z),
P is Z*X
; P = 1 ).
Then it will just print one answer.
(Your code leaves a `choice point' at every recursive call, because you have two disjuncts and no cut. Using if-then-else or a cut somewhere removes those. Then it depends on the interpreter what happens. Sicstus still asks if you want ((to try to find)) more answers.)
Semantic differences
Currently, there are 3 different versions of puissance/3, and I would like to show a significant semantic difference between some of them.
As a test case, I consider the query:
?- puissance(X, Y, Z), false.
What does this query mean? Declaratively, it is clearly equivalent to false. This query is very interesting nevertheless, because it terminates iff puissance/3 terminates universally.
Now, let us try the query on the different variants of the program:
Original definition (from the question):
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Accepted answer:
?- puissance(X, Y, Z), false.
false.
Other answer:
?- puissance(X, Y, Z), false.
ERROR: puissance/3: Arguments are not sufficiently instantiated
Obviously, the solution shown in the accepted answer yields a different result, and is worth considering further.
Here is the program again:
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Let us ask something simple first: Which solutions are there at all? This is called the most general query, because its arguments are all fresh variables:
?- puissance(X, Y, Z).
Y = 0,
Z = 1.
The program answers: There is only a single solution: Y=0, Z=1.
That's incorrect (to see this, try the query ?- puissance(0, 1, _) which succeeds, contrary to the same program claiming that Y can only be 0), and a significant difference from the program shown in the question. For comparison, the original program yields:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
ERROR: puissance/3: Arguments are not sufficiently instantiated
That's OK: On backtracking, the program throws an instantiation error to indicate that no further reasoning is possible at this point. Critically though, it does not simply fail!
Improving determinism
So, let us stick to the original program, and consider the query:
?- puissance(1, 1, Z).
Z = 1 ;
false.
We would like to get rid of false, which occurs because the program is not deterministic.
One way to solve this is to use zcompare/3 from library(clpfd). This lets you reify the comparison, and makes the result available for indexing while retaining the predicate's generality.
Here is one possible solution:
puissance(X, N, P) :-
zcompare(C, 0, N),
puissance_(C, X, N, P).
puissance_(=, _, 0, 1).
puissance_(<, X, N, P) :-
A #= N-1,
puissance(X, A, Z),
P #= Z*X.
With this version, we get:
?- puissance(1, 1, Z).
Z = 1.
This is now deterministic, as intended.
Now, let us consider the test case from above with this version:
?- puissance(X, Y, Z), false.
nontermination
Aha! So this query neither throws an instantiation error nor terminates, and is therefore different from all the versions that have hitherto been posted.
Let us consider the most general query with this program:
?- puissance(X, Y, Z).
Y = 0,
Z = 1 ;
X = Z,
Y = 1,
Z in inf..sup ;
Y = 2,
X^2#=Z,
Z in 0..sup ;
Y = 3,
_G3136*X#=Z,
X^2#=_G3136,
_G3136 in 0..sup ;
etc.
Aha! So we get a symbolic representation of all integers that satisfy this relation.
That's pretty cool, and I therefore recommend you use CLP(FD) constraints when reasoning over integers in Prolog. This will make your programs more general and also lets you improve their efficiency more easily.
You can add a cut operator (i.e. !) to your solution, meaning prolog should not attempt to backtrack and find any more solutions after the first successful unification that has reached that point. (i.e. you're pruning the solution tree).
puissance(_,0,1) :- !.
puissance(X,N,P) :- N>0,A is N-1, puissance(X,A,Z), P is Z*X.
Layman's Explanation:
The reason prolog attempts to see if there are any more solutions, is this:
At the last call to puissance in your recursion, the first puissance clause succeeds since P=1, and you travel all the way back to the top call to perform unification with P with the eventual value that results from that choice.
However, for that last call to puissance, Prolog didn't have a chance to check whether the second puissance clause would also be satisfiable and potentially lead to a different solution, therefore unless you tell it not to check for further solutions (by using a cut on the first clause after it has been successful), it is obligated to go back to that point, and check the second clause too.
Once it does, it sees that the second clause cannot be satisfied because N = 0, and therefore that particular attempt fails.
So the "false" effectively means that prolog checked for other choice points too and couldn't unify P in any other way that would satisfy them, i.e. there are no more valid unifications for P.
And the fact that you're given the choice to look for other solutions in the first place, exactly means that there are still other routes with potentially satisfiable clauses remaining that have not been explored yet.

Prolog List Squaring, Modifying element in List

I am trying to write a short Prolog program which takes a list of numbers and returns a list where all numbers have been squared.
Ie: [2,4,5] => [4,16,25]
My code so far:
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :-
list_of_squares(XS, M).
For some reason though Prolog doesn't like me squaring X while adding it to a list... Any thoughts on how I could do this?
You're not that far off, but you make two small mistakes:
Firstly, you mix element X with list L. Your first clause should be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
Secondly, you cannot perform an arithmetic function in list notation.
Your second clauses should be as follows:
list_of_squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
list_of_squares(Xs, Ys).
Thirdly, there is a more fundamental problem. With the first two fixes, your code works, but the base case, i.e. the first clause, is not that well chosen. (A) the code cannot process the empty list. (B) For a singleton list the code is needlessly nondeterministic, because both clauses apply. This is solved by choosing the base case wisely:
squares([], []).
squares([X|Xs], [Y|Ys]):-
Y is X ^ 2,
squares(Xs, Ys).
Here is a general method how you can localize such an error. First, let's start with your exemple:
?- list_of_squares([2,4,5],[4,16,25]).
false.
Oh no! It fails! There is a very general method what to do in such a situation:
Generalize the query
So we replace [4,16,25] by a new, fresh (ah, true freshness!) variable:
?- list_of_squares([2,4,5],L).
L = [2^2,4^2|25]
; false.
That's way better: Now you know that there is a "result", but that result it not what you expected.
Next,
Minimize the query
The list is way too long, so I will chop off some elements. Say, the first two:
?- list_of_squares([5],L).
L = 25
; false.
Again, wrong, but smaller. Now, where is the error for that? To get it
Specialize your program
list_of_squares([X], L) :-
L is X^2.
list_of_squares([X|XS], [X^2|M]) :- false,
list_of_squares(XS, M).
That program, again gives the same wrong answer! So in there is a bug in the visible part. What we expect is
?- list_of_squares([5],[25]).
false.
this to succeed. But where is the error? Again:
Generalize the query
?- list_of_squares([5],[X]).
false.
HET!
Now, you should realize that that rule might be:
list_of_squares([X], [Y]):-
Y is X ^ 2.
And the same (is)/2 should be used in the recursive rule. And, why not accept [].
I, personally, would rather write using library(lambda):
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX is X^2), Xs, Ys).
Or, even better, using library(clpfd)
list_of_squares(Xs, Ys) :-
maplist(\X^XX^(XX #= X^2), Xs, Ys).
Prolog doesn't have a 'functional' mindset, but some standard builtin predicate can help working with lists. In this case
list_of_squares(L,S) :- findall(Sq,(member(E,L),Sq is E*E),S).
?- list_of_squares([2,4,5], R).
R = [4, 16, 25].
in this case, member/2 play a role similar to lambda expressions, giving a 'name' to each element E available in L. findall/3 compute all solutions of its goal ,(member(E,L),Sq is E*E),, and collects results (the 'template' expression, that is, Sq).

Resources