Why do both predicates get evaluated? - prolog

I have this predicate with two clauses:
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
and I submit this to the interpreter:
?- abs(-5,W).
W = 5 ;
false.
?-
Why does it evaluate the second clause and return false? Is there a way around that?

You wrote two clauses that are disjoint on the 1st argument(X) and were surprised that Prolog backtracked into the 2nd one even though the first one was satisfied.
abs(X, Y) :- X < 0, Y is -X.
abs(X, X) :- X >= 0.
When the 1st clause was satisfied, the Prolog engine only knew that there was a 2nd clause that hadn't been evaluated; when you typed ";", it tried the 2nd clause, which failed. To see why, consider a slightly different (and not as good) version of your code:
abs2(X, Y) :- X =< 0, Y is - X.
abs2(X, Y) :- X >= 0, Y = X.
?- abs2(0, Y).
Y = 0 ;
Y = 0 ;
In this situation, even though the 1st clause succeeds, the 2nd clause can also succeed.
So, how to avoid this? It depends on what you want to accomplish. If you want to get all the answers, do something like this:
?- setof(W, abs(-5, W), Ws).
Ws = [5].
To print them all:
?- forall(abs(-5, W), format('W = ~q~n', [W])).
W = 5
If you want to tell the Prolog engine that your predicate is deterministic, you can use an if-then-else:
abs(X, Y) :-
( X < 0
-> Y is -X
; Y = X
).
This can also be written with a cut("!"), but it's often easier to understand with if-then-else.
And, if you're using the latest version of SWI-Prolog, you can use the "=>" notation:
abs(X, Y), X < 0 => Y is -X.
abs(X, Y) => true.

Related

Boolean unification in Prolog?

I am struggling alreay for a long time with the
following problem. I want to make the usual unification
of Prolog more smart.
Basically I want that certain variables understand that
for example 0 = ~1 and 1 = ~0. This doesn't work normally:
?- op(300, fy, ~).
true.
?- X = ~Y, Y = 0.
X = ~0,
Y = 0.
I know that that CLP(B) can do it:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
:- use_module(library(clpb)).
true.
?- sat(X=:= ~Y), Y = 0.
X = 1,
Y = 0.
But I require something more lightweight than loading a full CLP(B) library. Any ideas?
It seems that SWI-Prologs when/2 does the job. I am using
the Quine algorithm from here to partially evaluate a boolean expression.
I can then define a Boolean let/2 predicate:
let(X, Y) :-
eval(Y, H),
term_variables(H, L),
( L== [] -> X = H;
cond(L, R),
when(R, let(X, H))).
cond([X], nonvar(X)) :- !.
cond([X,Y|Z], (nonvar(X);T)) :-
cond([Y|Z], T).
The above predicate will reevaluate the expression assigned
to the variable X when ever some variable inside the expression
changes. The expression is associate with the variable X through when/2. Since we see when/2 in the top-level, we see the associated expression:
?- let(X, ~Y).
when(nonvar(Y), let(X, ~Y))
?- let(X, Y+Z).
when((nonvar(Y); nonvar(Z)), let(X, Y+Z))
And we can also do our use case and even more:
?- let(X, ~Y), Y = 0.
X = 1,
Y = 0.
?- let(X, Y+Z), Y = 0.
Y = 0,
when(nonvar(Z), let(X, Z))
?- let(X, Y+Z), Y = 0, Z = 1.
X = 1,
Y = 0,
Z = 1

Prolog, X element before element Y on list [duplicate]

This question already has answers here:
Prolog, X before Y in a List
(4 answers)
Closed 6 years ago.
I am going to write predicate which is true iff only and only when element X occurs before Y on list L
before(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
Above, you can see my solution. What do you think about it ?
When it comes to my specific question:
My predicate returns true when there is exists at least one pair that Y followed X. How to define predicate such that it is true for each pair ?
The solution you show works for the "if one exists" case, but is somewhat imperative in nature. That is, it's a little bit like a C program translated to Prolog. Imperative means you are telling the computer, using the programming language, what steps to execute in order to achieve your results.
To be more declarative or relational, your "exists" solution could be expressed nicely as a DCG:
... --> [].
... --> [_], ... .
before(X, Y) --> ... , [X], ... , [Y], ... .
(NOTE: You can in Prolog have a predicate named ..., which is shown here.) This describes the relationship of X and Y in the list. It does not describe steps to execute, but instead describes the relationship of X and Y in a sequence. This solution has been shown before on SO.
Following this approach (where we describe the relationship of X and Y), one way (not necessarily the only way) to express that all the X precede all the Y would be:
before_all(X, Y) -->
{ dif(X,Y) },
any_sequence_but(Y), [X], any_sequence_but(Y), [Y], any_sequence_but(X).
any_sequence_but(_) --> [].
any_sequence_but(Y) --> [X], { dif(X,Y) }, any_sequence_but(Y).
Which yields a solution like this:
?- phrase(before_all(X,Y), [b,a,b,c,a,b,d]).
X = b,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
X = c,
Y = d ;
X = a,
Y = d ;
X = b,
Y = d ;
false.
?-
If the condition should hold for all pairs, the condition should hold for at least one pair, while its converse shouldn't be true for any pair.
I took the liberty of renaming your before/3 to beforeSome/3.
beforeSome(L, X, Y) :-
nth1(PX, L, X),
nth1(PY, L, Y),
PX < PY.
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).
Which yields the desired results:
?- beforeAll([1,2,3,1,4,5], 1, 4).
true.
?- beforeAll([1,2,3,1,4,5], 1, 2).
false.
Please note that your use of nth1/3 precludes it being used with uninstantiated variables. In other words, beforeAll([1,2,3,1,4,5], X, Y). is false.
A better implementation of beforeSome/3 would be something like
beforeSome([X|T], X, Y) :-
member(Y, T).
beforeSome([_|T], X, Y) :-
beforeSome(T, X, Y).
% no change needed, but repeated here for completeness' sake
beforeAll(L, X, Y) :-
beforeSome(X,Y),
not(beforeSome(L, Y, X)).

Prolog - if condition 1 AND condition 2 do x

I want to write the equivalent psudo-function in prolog:
function underhundred(X){
if (X >= 0 && X <=100) return 1;
else return 0;
}
I tried writing this but it does not compile:
underhundred(X,L) :- L is (X => 0, X =< 100 -> L = 1; L = 0) .
What would be the proper way of writing this without using prolog between predicate?
If you indeed want to use the goals L=1 and L=0 and X is an integer, use clpfd!
:- use_module(library(clpfd)).
Reification works like a charm!
?- X in 0..100 #<==> L.
L in 0..1, X in 0..100#<==>L.
What if X gets instantiated?
?- X in 0..100 #<==> L, X=(-7).
L = 0, X = -7. % out of bounds: -7 < 0 =< 100
?- X in 0..100 #<==> L, X=55.
L = 1, X = 55. % within bounds: 0 =< 55 =< 100
?- X in 0..100 #<==> L, X=111.
L = 0, X = 111. % out of bounds: 0 =< 100 < 111
A Prolog query succeeds or fails. If it succeeds it will return the bindings it made to be true.
You can write this predicate using clpfd as:
:-use_module(library(clpfd)).
under_hundred_clpfd(X):-
X in 0..100.
(You might prefer a name such as between_0_100?, if you literally want under 100 then you can use X in inf..99).
Some queries:
?-under_hundred_clpfd(5).
true.
?-under_hundred_clpfd(101).
false.
?-under_hundred_clpfd(X).
X in 0..100.
A traditional way to write this is:
under_hundred(X):-
X>=0,
X=<100.
But this way does not work for uninstantiated variables.
?-under_hundred(X).
ERROR: >/2: Arguments are not sufficiently instantiated
So like you say you might have to put a between/3 or length/2 goal to get a solution or similar construct.
underhundred(X):-
length(_,X),
X>=0,
X=<100.
This is not a very good solution as on back tracking it will get into an infinite loop. between/3 behaves better but you don't want it :).
If the main point of the question is how to write an if-then-else construct in Prolog, then a reasonable answer along the lines of the proposed definition is:
underhundred(X,L) :-
( X >= 0, X =< 100 )
-> L = 1
; L = 0.
This will only be useful if underhundred(X,L) is called after X has been sufficiently instantiated.

Display first 100 Integers in Prolog

I am very new to prolog and I am trying to code a simple program which will display the first 100 integers.
is_integer(0).
is_integer(X) :-
is_integer(Y),
( Y >= 100, ! ; X is Y + 1 ).
It works well but when we ask if 2.1 is an integer then it replies "true". This is because 2.1 is between 0 and 100.
But I want a program which will strictly display the first 100 Integers only.Could someone help me with this please.
Thanks!
I think this matches your style in the question if you don't want to use predefined functions like between(0, 100, X):
between0_100(X) :-
(var(X) -> true ; X >= 0), % either X is unbound or >= 0.
between0_100(0, X).
between0_100(X, X).
between0_100(X, Y) :-
Z is X + 1, % increment X
Z =< 100, % and test if it is <= 100
between0_100(Z, Y). % recurse
?- between0_100(X).
X = 0 ;
X = 1 ;
X = 2 ;
…
X = 98 ;
X = 99 ;
X = 100 ;
false.
?- between0_100(2.1).
false
What do you mean by "display"?
The (very standard) predicate between/3 is defined along the lines of:
between(Lower, Upper, N) is true when N >= Lower and N =< Upper. If N is an integer, it will succeed or fail, and throw an error if it is not an integer. If N is a free variable it will enumerate solutions by backtracking. I am quite certain you can find reasonable implementations of between/3 elsewhere on StackOverflow.
Or do you mean that you type in:
?- first_100_ints.
And you get:
0
1
2
3
4
...
99
?
You could do this as follows:
first_100_ints :-
next_int(0, 100).
next_int(X, Upper) :-
( X < Upper
-> format('~d~n', [X]),
succ(X, X1),
next_int(X1, Upper)
; true
).
This is one "cheap" way to do it. But keep in mind that this is not how you would want to write a Prolog program, normally. One somewhat better way would be to use the built-ins between/3 and forall/3:
?- forall(between(0, 99, X), format('~d~n', [X])).
This is equvalent to:
?- \+ (between(0, 99, X), \+ format('~d~n', [X])).
which reads something along the lines of, "There is no number between 0 and 99 (inclusive) for which you cannot print out the number". See here.
There are other things you can do, depending on what your exact goal is.
I second #Kay's answer. If it is possible, don't use side-effects and use the prolog-toplevel instead!
If your Prolog implementation offers clpfd, you could do it like this:
:- use_module(library(clpfd)).
?- X in 0..100, indomain(X).
X = 0. ;
X = 1 ;
X = 2 ;
% % ... lots of more answers ...
X = 99 ;
X = 100 ;
false. % query terminates universally

Why does this query unify with this clause in Prolog?

I think I have a fundamental misunderstanding about unification. Here are my two clauses:
test(func(X), X, 1) :- X == X.
test(func(X), Y, 0) :- X \== Y.
So- If I query test(func(X), Y, D), I would expect it to only be provable with the second clause, and D will be 0. This is because (I think\I am trying to) ensure that X must be equal to X, in the first clause. So my query shouldn't unify because X is not the same as Y. I thought == tests that the two operands are the same variables. And X and Y clearly aren't.
But the output:
| ?- test(func(X), Y, D).
D = 1
Y = X ? ;
D = 0
So it is saying that it unifies with the first clause if Y = X. But, Y is not equal to X. What am I misunderstanding here?
Your first answer, D = 1, Y = X accords with your first definition. I think you're expecting that when you query ?- test(func(X), Y, D). it should fail for the first definition, because the X and Y are different variables, but the first definition should only succeed if the two variables are identical.
However, in the head of your clause, you have the same variable appearing twice: test(func(X), X, 1) :- X == X. (As #CapelliC pointed out, X == X is superfluous here.) When you query ?- func(func(X), Y, D)., Prolog tries to unify this clause with the head of your first rule. It unifies func(X) with func(X) and Y with X and 1 with 1. Once this pattern-matching unification has succeeded, it then tests the body of the rule to see if the criteria are met. Since Y has been unified with X, the two variables will match the strict equality condition---during the pattern matching, you've unified Y with the same variable as X.
Note the following two queries:
?- X == Y.
false.
?- Y = X, X == Y.
X = Y.
The second is similar to what's happening with the query that's confusing you. If you rewrite your first rule in accordance with #CapelliC's suggestion,
test(func(X), Y, 1) :- X == Y.
Then it will function as expected, because, in this case, a free variable in the second argument will be unified with a different variable than that within the func/1 term, and then the two variables won't satisfy strict equality (but if the two variables are unified with a ground term, they will pass).
X == X it's a sort of tautology (always true), and clearly your first clause could equivalently be
test(func(X), X, 1).
I think you should write it like the second one
test(func(X), Y, 1) :- X == Y.

Resources