0
votes

I've started learning PROLOG and I have a problem with a very basic example. I'm using SWI PROLOG and the code is as follows:

is_true(a).
is_true(c).
is_true(d).
is_false(b).
is_false(e).

and(A,B) :- is_true(A),is_true(B).
nand(A,B) :- \+(and(A,B)).

Then:

[imanol@I56106 prolog]$ swipl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.4)
Copyright (c) 1990-2013 University of Amsterdam, VU Amsterdam
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software,
and you are welcome to redistribute it under certain conditions.
Please visit http://www.swi-prolog.org for details.

For help, use ?- help(Topic). or ?- apropos(Word).

?- consult(test).
% test compiled 0.00 sec, 8 clauses
true.

?- and(a,X).
X = a ;
X = c ;
X = d.

Everything is great ATM, I made PROLOG backtrack all the possible values that comply the goal and(A,B) for A=a. But if I try with the goal nand(A,B):

?- nand(a,X).
false.

Either it thinks that the goal is impossible or it doesn't backtrack, and I haven't got the slightest clue why. :/

Does someone know what I'm doing wrong?

Thanks in advance.

PS: I also tried with:

nand(A,B) :- not(and(A,B)).

And it yields the same result.

EDIT: Seeing that my question is cryptic for some:

I'd like PROLOG to give me a list of values for the variables A and B which make and(A,B) unsatisfiable

EDIT2: I expect PROLOG to tell me:

?- nand(a,X).
    X = e ;
    X = b.
2
I edited the question - Imanol Barba Sabariego
We are getting there. Now a question for you: at what point in your program at the moment do you refer to the predicate is_false/1? - user1812457
The point in the program at which I refer to the predicate is_false/1 is line 4 - Imanol Barba Sabariego
I also tried this BTW is_false(X) :- not(is_true(X)). didn't work - Imanol Barba Sabariego
and I also tried not(is_true(b)). - Imanol Barba Sabariego

2 Answers

1
votes

From the SWI-Prolog documentation:

"... True if `Goal' cannot be proven ..."

In other words: \+(and(A, B)) will only succeed if and(A, B) fails. In other words, if there is a solution for and(A, B), \+(and(A, B)) will fail.

From what I see, there is a solution for both and(a, X), and for and(A, B).

Try any query for arguments that are not explicitly declared as is_true/1.

Try to google for "negation as failure", and "closed world assumption". Both have wikipedia articles that are worth reading.

Be careful when you mix boolean logic and Prolog. They don't make the same assumptions.

To your problem: you have a bunch of logical variables. Some of them are true, some of them are false. You want to be able to calculate the truth tables. Say and(A, B) should succeed when the output column is true, and fail otherwise. At this point, you are already mixing up two different concepts:

  1. Logical TRUE and FALSE
  2. Prolog's success and failure

This is actually wrong enough that I would suggest against it. Instead:

and(f, f, f).
and(f, t, f).
and(t, f, f).
and(t, t, t).

not(t, f).
not(f, t).

nand(A, B, R) :- and(A, B, R0), not(R0, R).

val(a, t). val(c, t). val(d, t).
val(b, f). val(e, f).

solve(and(A, B), R) :- val(A, VA), val(B, VB), and(VA, VB, R).
% solve(nand...) as exercise

and so on.

Then, you can have much more informative queries:

?- solve(and(a, c), R).
R = t.

?- solve(and(a, X), R).
X = a,
R = t ;
X = c,
R = t ;
X = d,
R = t ;
X = b,
R = f ;
X = e,
R = f ;
false.

?- solve(nand(a, X), R).
X = a,
R = f ;
X = c,
R = f ;
X = d,
R = f ;
X = b,
R = t ;
X = e,
R = t ;
false.
1
votes

A simplistic approach would be to introduce a predicate that succeeds for a valid variable. So to your existing predicates, add:

is_valid(X) :- is_true(X) ; is_false(X).

Then the nand/2 predicate can work within that domain and confine the universe of possible values. Otherwise, \+ and(A, B) has no idea what values to choose from to determine failure of and(A, B):

nand(A, B) :- is_valid(A), is_valid(B), \+ and(A, B).

| ?- nand(a, X).

X = b ? ;

X = e ? ;

no

Stated another way, is_valid/1 provides a means for nand/2 to generate the possible options for which \+ and(A, B) can be tested.

You could just as reasonably apply this "confining of the universe" to the other predicates, such as and/2: and(A, B) :- is_valid(A), is_valid(B), is_true(A), is_true(B)., but you can see that this would be redundant.