Prolog - print true or false in print_solution write method - prolog

I want to print true or false based on some predicate predicate passing. For example, in Greek mythology Athena is not a descendant of Poseidon. I have all of the facts and rules correct to prove it as such, but cannot simply print in the print_solution method whether the predicate is true or not.
I have the rule descendant(athena, poseidon) that will print false in the interpreter as a single statement. E.g. false is printed if I:
$ prolog
['greek_mythology.pl'].
descendant(athena, poseidon).
false
I now want to write the same in my print_solution method:
print_solution :-
write('Athena is a descendant of Poseidon: '), write(?????), nl.
I tried assigning a variable in the solution and printing that:
print_solution :-
Z :- descendant(athena, poseidon),
write('Athena is a descendant of Poseidon: '), write(Z), nl.
but I get the error:
ERROR: /.../greek_mythology.pl:164:17: Syntax error: Operator priority clash
Out of desperation I tried checking to see if poseidon was in the list of descendant(athena, X):
setof(X, descendant(athena, X), Z), // [gaia,kronos,oranos,rheia,zeus]
member(poseidon, Z).
but that just gives back:
Z = [poseidon|_G3320] .
which I don't understand. Apparently member/2 only works on lists, and Z is apparently not a list:
is_list(Z).
false.
How can I simply print true or false in the write function if the predicate returns passes like it does in the interpreter console? Desired output: Athena is a descendant of Poseidon: false.

You can use if/then/else construct in Prolog also
print_solution :-
( descendant(athena, poseidon)
-> Z = true
; Z = false
),
write('Athena is a descendant of Poseidon: '), write(Z), nl.
seems also could be more useful if parametrized
print_solution(Desc, Anc) :-
( descendant(Desc, Anc)
-> Z = true
; Z = false
),
format('~w is a descendant of ~w: ~w~n', [Desc, Anc, Z]).
print_solution :- print_solution(athena, poseidon).

I think (not absolutely sure) that what you want is reification of the success or failure of a query to a truth value. A naive way to do it would be:
goal_success(Goal, true) :-
Goal.
goal_success(Goal, false) :-
\+ Goal.
(This has problems but read on)
Then, you can use it like this:
?- goal_success(descendant(athena, poseidon), S),
/* write whatever */, write(S).
However, what you are trying to do is basically write your own meta-interpreter, and I am not sure it is really that useful. After all, what you show in your question is exactly how you would expect to interact with the Prolog top level (the Prolog interactive prompt). As a programmer (a human) what you want from Prolog is answers to your questions. What you give Prolog, however, is queries, and you get solutions to these queries. Your question is:
Is Athena a descendant of Poseidon?
You evaluate the query:
?- descendant(athena, poseidon).
false.
There is no solution to this query (let's not go into the whole "closed world assumption" discussion now, it is enough to say that not being able to find a proof means that the opposite is true...)
So we interpret this as:
Athena is not a descendant of Poseidon.
Usually, this should be enough. This is why it seems that you want to extend the Prolog top level, and write your own interpreter on top of it, which is of course fine, but more involved. Once you go down that road, you would like to interact with this interpreter like this maybe?
??- Is Athena a descendant to Poseidon?
?>> No, she is not!
Anyway, if you search the internet for "Prolog meta interpreter" you will get enough to get you started. "The Art of Prolog" by Sterling & Shapiro has a whole chapter on that, too.

Related

PROLOG - Get a list of all the rules an entity verifies

I'm formalizing linguistic data into predicates and entities and doing some reasoning in prolog. Imagine I begin with:
breathe(X) :- snore(X).
sleep(X) :- snore(X).
rest(X) :- sleep(X).
live(X) :- breathe(X); eat(X); sleep(X).
snore(john).
sleep(lucy).
My data can get big enough and I would like to get a list of entities and predicates in order to iterate them and check how many predicates an entity verifies, the output can be lists like:
[john, [snore, breathe, sleep, rest, live]]
[lucy, [sleep, rest]]
or predicates
participant(john, [snore, breathe, sleep, rest, live]).
participant(lucy, [sleep, rest]).
Thanks for your help, I have no clue at this moment.
Representing live knowledge about an abstract world can get messy. There are a lot of different possibilities, and a lot of variance depending of which Prolog system you're using.
Here is an example of your code running in SWI-Prolog, but the same idea should work (more or less) unchanged on any Prolog out there that provides call/N and setof/3 builtins.
:- module(list_entities_that_verify_a_pred,
[participant/2]).
:- redefine_system_predicate(sleep/1).
:- discontiguous breathe/1,sleep/1,rest/1,live/1,snore/1.
breathe(X) :- snore(X).
sleep(X) :- snore(X).
rest(X) :- sleep(X).
live(X) :- breathe(X); /* eat(X);*/ sleep(X).
snore(john).
sleep(lucy).
to_verify(breathe).
to_verify(sleep).
to_verify(rest).
to_verify(live).
to_verify(snore).
participant(Person,Verified) :-
setof(Pred,(to_verify(Pred),call(Pred,Person)),Verified).
First, note I have commented the call to eat/1, to avoid a missing definition exception, so we can try to call the partecipant/2 predicate:
?- participant(P,L).
P = john,
L = [breathe, live, rest, sleep, snore] ;
P = lucy,
L = [live, rest, sleep].
From an architecture viewpoint, the main point to note it's the introduction of to_verify/1, to ease the workflow.
An alternative is using forward chaining using Constraint Handling Rules, an underappreciated paradigm of computation.
This is done using SWI-Prolog's CHR library. The rule engine is implemented "on top of Prolog" and adding a rule to the "constraint store" looks like calling a Prolog goal. The "constraint store" holding the current state of computation disappears once the goal completes.
Note that I'm currently not 100% certain of CHR semantics (it seems my brain is hardwired to read Prolog now) but this code seems to work.
In file sleep.pl:
:- module(forward,[
snore/1,
sleep/1,
collect/2,
pull/2
]).
:- use_module(library(chr)).
:- chr_constraint snore/1, sleep/1, breathe/1.
:- chr_constraint eat/1, live/1, rest/1, collect/2, pull/2.
snore(X) ==> breathe(X).
snore(X) ==> sleep(X).
sleep(X) ==> rest(X).
breathe(X) ==> live(X).
eat(X) ==> live(X).
sleep(X) ==> live(X).
live(X) \ live(X) <=> true. % eliminates duplicates
collect(Who,L),snore(Who) <=> collect(Who,[snore|L]).
collect(Who,L),sleep(Who) <=> collect(Who,[sleep|L]).
collect(Who,L),breathe(Who) <=> collect(Who,[breathe|L]).
collect(Who,L),eat(Who) <=> collect(Who,[eat|L]).
collect(Who,L),live(Who) <=> collect(Who,[live|L]).
collect(Who,L),rest(Who) <=> collect(Who,[rest|L]).
pull(Who,L) \ collect(Who2,L2) <=> Who = Who2, L = L2.
Now we just need to start SWI-Prolog, and issue these commands:
?- [sleep].
true.
?- sleep(lucy),
collect(lucy,[]),
pull(Who,L).
Who = lucy,
L = [rest,live,sleep],
pull(lucy,[rest,live,sleep]).
?- snore(john),
collect(john,[]),
pull(Who,L).
Who = john,
L = [rest,live,breathe,sleep,snore],
pull(john,[rest,live,breathe,sleep,snore]).
You asked in a comment to Carlo's answer:
Is there a way to expose the eat predicate and the like? It looks like
I'm going to have a lot of unmatched predicate networks like owl and
proton because I'm going to use few facts and a lot of semantic
relations from Wordnet.
The issue here seems to be one of closed-world assumption (CWA) where predicates are declared (and thus can be called without generating errors) but not necessarily defined. In this case, as per CWA, what we cannot prove is true, is assumed to be false. E.g. the eat/1 predicate in your example or the "lot of unmatched predicate networks" in your comment.
A possible solution would be to define your entities as Logtalk objects that implement a protocol (or a set of protocols) that declare all the predicates you want to use. Reusing your example:
:- protocol(predicates).
:- public([
breathe/0, sleep/0, rest/0, live/0,
snore/0, eat/0
]).
:- end_protocol.
:- category(generic,
implements(predicates)).
breathe :- ::snore.
sleep :- ::snore.
rest :- ::sleep.
live :- ::breathe; ::eat; ::sleep.
:- end_category.
:- object(john, imports(generic)).
snore.
:- end_object.
:- object(lucy, imports(generic)).
sleep.
:- end_object.
If we ask an entity (object) about a predicate that it doesn't define, the query will simply fail. For example (using SWI-Prolog as backend here but you can use most Prolog systems; assuming the code above is saved in a code.lgt file):
$ swilgt
...
?- {code}.
...
?- lucy::eat.
false.
If we want to find all objects that satisfy e.g. the sleep/0 predicate:
?- findall(Object,
(current_object(Object),
conforms_to_protocol(Object, predicates),
Object::sleep),
Objects).
Objects = [john, lucy].
If we want to query all predicates satisfied by the objects (here with the simplifying assumption that all those predicates have zero arity):
?- setof(
Name,
Arity^(current_object(Object),
conforms_to_protocol(Object, predicates),
Object::current_predicate(Name/Arity),
Object::Name),
Predicates
).
Object = john,
Predicates = [breathe, live, rest, sleep, snore] ;
Object = lucy,
Predicates = [live, rest, sleep].
But, at least for the most common queries, handy predicate definitions would preferably be added to the generic category.
P.S. For more on the closed-world assumption and predicate semantics and also why Prolog modules fail to provide a sensible alternative solution see e.g. https://logtalk.org/2019/09/30/predicate-semantics.html

Prolog order of clauses causes pathfinding to fail

I am developing a path finding algorithm in Prolog, giving all nodes accessible by a path from a starting node. To avoid duplicate paths, visited nodes are kept in a list.
Nodes and neighbors are defined as below:
node(a).
node(b).
node(c).
node(d).
node(e).
edge(a,b).
edge(b,c).
edge(c,d).
edge(b,d).
neighbor(X,Y) :- edge(X,Y).
neighbor(X,Y) :- edge(Y,X).
The original algorithm below works fine:
path2(X,Y) :-
pathHelper(X,Y,[X]).
pathHelper(X,Y,L) :-
neighbor(X,Y),
\+ member(Y,L).
pathHelper(X,Y,H) :-
neighbor(X,Z),
\+ member(Z,H),
pathHelper(Z,Y,[Z|H]).
This works fine
[debug] ?- path2(a,X).
X = b ;
X = c ;
X = d ;
X = d ;
X = c ;
false.
however, when changing the order of the two clauses in the second definition, such as below
pathHelper(X,Y,L) :-
\+ member(Y,L),
neighbor(X,Y).
When trying the same here, swipl returns the following:
[debug] ?- path2(a,X).
false.
The query doesn't work anymore, and only returns false. I have tried to understand this through the tracecommand, but still can't make sense of what exactly is wrong.
In other words, I am failing to understand why the order of neighbor(X,Y)and \+ member(Y,L)is crucial here. It makes sense to have neighbor(X,Y) first in terms of efficiency, but not in terms of correctness to me.
You are now encountering the not so clean-cut borders of pure Prolog and its illogical surroundings. Welcome to the real world.
Or rather, not welcome! Instead, let's try to improve your definition. The key problem is
\+ member(Y, [a]), Y = b.
which fails while
Y = b, \+ member(Y,[a]).
succeeds. There is no logic to justify this. It's just the operational mechanism of Prolog's built-in (\+)/1.
Happily, we can improve upon this. Enter non_member/2.
non_member(_X, []).
non_member(X, [E|Es]) :-
dif(X, E),
non_member(X, Es).
Now,
?- non_member(Y, [a]).
dif(Y,a).
Mark this answer, it says: Yes, Y is not an element of [a], provided Y is different from a. Think of the many solutions this answer includes, like Y = 42, or Y = b and infinitely many more such solutions that are not a. Infinitely many solutions captured in nine characters!
Now, both non_member(Y, [a]), Y = b and Y = b, non_member(Y, [a]) succeed. So exchanging them has only influence on runtime and space consumption. If we are at it, note that you check for non-memberness in two clauses. You can factor this out. For a generic solution to this, see closure/3. With it, you simply say: closure(neighbor, A,B).
Also consider the case where you have only edge(a,a). Your definition fails here for path2(a,X). But shouldn't this rather succeed?
And the name path2/2 is not that fitting, rather reserve this word for an actual path.
The doubt you have is related to how prolog handle negation. Prolog uses negation as failure. This means that, if prolog has to negate a goal g (indicate it with not(g)), it tries to prove g by executing it and then, if the g fails, not(g) (or \+ g, i.e. the negation of g) succeeds and viceversa.
Keep in mind also that, after the execution of not(g), if the goal has variables, they will not be instantiated. This because prolog should instantiate the variables with all the terms that makes g fail, and this is likely an infinite set (for example for a list, not(member(A,[a]) should instantiate the variable A with all the elements that are not in the list).
Let's see an example. Consider this simple program:
test:-
L = [a,b,c],
\+member(A,L),
writeln(A).
and run it with ?- trace, test. First of all you get a Singleton variable in \+: A warning for the reason i explained before, but let's ignore it and see what happens.
Call:test
Call:_5204=[a, b]
Exit:[a, b]=[a, b]
Call:lists:member(_5204, [a, b])
Exit:lists:member(a, [a, b]) % <-----
Fail:test
false
You see at the highlighted line that the variable A is instantiated to a and so member/2 succeeds and so \+ member(A,L) is false.
So, in your code, if you write pathHelper(X,Y,L) :- \+ member(Y,L), neighbor(X,Y)., this clause will always fail because Y is not sufficiently instantiated. If you swap the two terms, Y will be ground and so member/2 can fail (and \+member succeeds).

Tree leaf traversal in Prolog

I experience some issues when I'm training prolog exercises,the problem below is,
The predicate defines what it means to be a tree, and can be used to test whether a term is a tree:
tree(t(L,R)) :- tree(L), tree(R).
tree(T) :- T\=t(_ , _).
By using this predicate you can find an element in a tree, (called a leaf):
leaf(t(L,R),E) :- leaf(L,E); leaf(R,E).
leaf(T,T) :- T\=t(_ , _).
So here have two problem, first is write predicate elements/2 that produces a list of the elements as they are found in the leafs of a tree in the first argument in a left-to-right order!
The second is write a predicate same content/2 that succeeds exactly when two trees contain the same elements in the same order! Duplicates are significant.
Hope can get anyone good at prolog can help me, thanks a lot.
Both tree/1 and leaf/1 are defaulty1,2!
Why not use a cleaner representation like this?
is_tree(leaf(_)).
is_tree(bin(L,R)) :-
is_tree(L),
is_tree(R).
Note that:
is_tree/1 is more versatile than tree/1 and leaf/1: it can generate as well as test trees—and even do a little of both (if the argument is partially instantiated).
is_tree/1 never gives logically unsound answers—no matter which "mode" it is used in.
Some sample uses of is_tree/1:
?- is_tree(T). % generate
T = leaf(_A)
; T = bin(leaf(_A),leaf(_B))
; T = bin(leaf(_A),bin(leaf(_B),leaf(_C)))
; T = bin(leaf(_A),bin(leaf(_B),bin(leaf(_C),leaf(_D))))
...
?- is_tree(bin(leaf(1),bin(leaf(2),3))). % test
false.
?- is_tree(bin(leaf(1),bin(leaf(2),leaf(3)))). % test
true.
?- T = bin(bin(leaf(1),2),_), is_tree(T). % do both (or at least try)
false.
?- T = bin(bin(leaf(1),leaf(2)),_), is_tree(T). % do both
T = bin(bin(leaf(1),leaf(2)),leaf(_A))
T = bin(bin(leaf(1),leaf(2)),bin(leaf(_A),leaf(_B)))
T = bin(bin(leaf(1),leaf(2)),bin(leaf(_A),bin(leaf(_B),leaf(_C))))
...
Coming back to your question on how to implement elements/2 and content/2... Use dcg!
leaves(leaf(E)) --> [E].
leaves(bin(L,R)) --> leaves(L), leaves(R).
same_content(A,B) :-
phrase(leaves(A),Ls),
phrase(leaves(B),Ls).
Sample query:
?- same_content(bin(leaf(1),bin(leaf(2),leaf(3))),
bin(bin(leaf(1),leaf(2)),leaf(3))).
true.
Footnote 1: This rock-solid treatise on teaching Prolog discusses many common obstacles, including defaultyness.
Footnote 2: In this answer #mat explains on how defaultyness in Prolog impedes declarative debugging and reasoning.

Prolog notBetween function

I need some help here with Prolog.
So I have this function between that evaluates if an element is between other two.
What I need now is a function that evaluates if a member is not between other two, even if it is the same as one of them.
I tried it :
notBetween(X,Y,Z,List):-right(X,Y,List),right(Z,Y,List). // right means Z is right to Y and left the same for the left
notBetween(X,Y,Z,List):-left(X,Y,List),left(Z,Y,List).
notBetween(X,Y,Z,List):-Y is Z;Y is X.
I am starting with Prolog so maybe it is not even close to work, so I would appreciate some help!
When it come to negation, Prolog behaviour must be handled more carefully, because negation is 'embedded' in the proof engine (see SLD resolution to know a little more about abstract Prolog). In your case, you are listing 3 alternatives, then if one will not be true, Prolog will try the next. It's the opposite of what you need.
There is an operator (\+)/2, read not. The name has been chosen 'on purpose' different than not, to remember us that it's a bit different from the not we use so easily during speaking.
But in this case it will do the trick:
notBeetwen(X,Y,Z,List) :- \+ between(X,Y,Z,List).
Of course, to a Prolog programmer, will be clearer the direct use of \+, instead of a predicate that 'hides' it - and requires inspection.
A possibile definition of between/4 with basic lists builtins
between(X,Y,Z,List) :- append(_, [X,Y,Z|_], List) ; append(_, [Z,Y,X|_], List).
EDIT: a simpler, constructive definition (minimal?) could be:
notBetween(X,Y,Z, List) :-
nth1(A, List, X),
nth1(B, List, Y),
nth1(C, List, Z),
( B < A, B < C ; B > A, B > C ), !.
EDIT: (==)/2 works with lists, without side effects (it doesn't instance variables). Example
1 ?- [1,2,3] == [1,2,3].
true.
2 ?- [1,2,X] == [1,2,X].
true.
3 ?- [1,2,Y] == [1,2,X].
false.

Negation and testing for a unique set in Prolog

I've just started experimenting with Prolog, and I was trying to write a rule to find out whether a list contained only unique elements. I got it working in the second variation (by negating a positive test), but I've completely failed to understand why the first variation doesn't work.
Given this file:
uniqueElements([X|Y]) :-
notmember(X, Y),
uniqueElements(Y).
notmember(X, Y) :-
\+ member(X, Y).
hasRepeatedElements([X|Y]) :-
(
member(X, Y) ->
true
; hasRepeatedElements(Y)
).
uniqueElements_2(X) :-
\+ hasRepeatedElements(X).
The GNU Prolog interpreter gives these responses:
| ?- uniqueElements([1,2,3]).
no
| ?- uniqueElements([1,2,3,2,3]).
no
| ?- uniqueElements_2([1,2,3]).
yes
| ?- uniqueElements_2([1,2,3,2,3]).
no
Why is the first response 'no'? (I would have expected member to return false, be negated to true, and thus have notmemeber return true on each iteration of uniqueElements). I guess I'm expecting '\+' to behave like '!' does in a C if clause, or the 'not' keyword in Python. Is this a misunderstanding?
In uniqueElements, you haven't provided the base case for the recursion:
uniqueElements([]).
Without that clause, when a particular call chain gets to the empty list case, it doesn't find any applicable clauses, which means fail in Prolog. Meaning, "unprovable". So, your call uniqueElements([1,2,3]) has produced an equivalent of true && true && true && false.
Now it should work.
hasRepeatedElements doesn't have a clause defined for the base case either, but its failure in finding whether there were repeated elements in an empty list [] is consistent with its semantics - it should have found that there are no repeated elements in empty list, in the first place.
In Prolog, "not" means "can't prove that ...".

Resources