How to chain multiple IF statements in logic programming? - prolog

I want to update my knowledge base after receiving a new state,
not((hasBeenVisited(X-1, Y)); not(wall(X-1, Y)) -> asserta(isDangerous(X-1, Y));
not(((hasBeenVisited(X+1, Y)); not(wall(X+1, Y)) -> asserta(isDangerous(X+1, Y));
not((hasBeenVisited(X, Y-1)); not(wall(X, Y-1)) -> asserta(isDangerous(X, Y-1));
not((hasBeenVisited(X, Y+1)); not(wall(X, Y+1)) -> asserta(isDangerous(X, Y+1));
problem with my code is that if the first line evaluates to true, then, the next lines are not evaluated, because of the logical OR ";".
If I were to change the ";" to logical AND ",", then if one of the conditions fail, the entire predicate returns false instead of true.
How do I chain multiple IFs statements? In procedural programming, we can do something like this:
if condition1 then statements1;
if condition2 then statements2;
if condition3 then statement3;
...
Should I even do that with prolog because I am still thinking in terms of procedural programming...

Your imperative example:
if condition1 then statements1;
if condition2 then statements2;
if condition3 then statements3;
becomes this shape:
(condition1 -> statements1 ; true),
(condition2 -> statements2 ; true),
(condition3 -> statements3 ; true).
with "code blocks" wrapped in () parens and making sure there is always a true whether the condition holds or not, so the block is true AND the next block can run.
You're right that coding in this way with imperative rules and state updates is fighting against the design of Prolog, and not leaning on its strengths. Also X+1 doesn't work the way you are using it, and I wonder if you are thinking that isDangerous(X+1, Y) will return a value like it was a function call and that return goes into asserta(<here>)? If so, that won't happen either.
Probably what you are being pushed towards is building a list of movements to get through a maze, and should be leaning on Prolog's backtracking to find the walls and dangerous places, step back from them and go another way.

Related

Prolog if statement without else

I have seen similar previous posts, but I seem to still be stuck. My current if statement, even when it fails, outputs the "if true" code. So I'd like to ask what the proper syntax is if I don't want to do anything else if the condition turns to be false.
My code that fails:
(Disease == malaria
-> (patient_age(y)
-> writeln('Since patient is young, likelihood of malaria increases.')
; true)
;
Disease == tuberculosis
-> (patient_age(e)
-> writeln('Since patient is old, likelihood of tuberculosis increases.')
; true)
).
What happens is that, even if patient_age() is false, the writeln() statement is still executed. I have attempted replacing the "false code" with another writeln() statement, which did not display. I apologize that this has been asked before. Thank you very much.
It would be more declarative, idiomatic, and clear to rewrite the code to avoid the use of the if-then-else control construct. For example:
% likelihood(Disease, PatientAge)
likelihood(malaria, y) :-
writeln('Since patient is young, likelihood of malaria increases.').
likelihood(tuberculosis, e) :-
writeln('Since patient is old, likelihood of tuberculosis increases.').
Still, it would likely be best to move the written messages to a predicate that calls the likelihood/2 predicate. For example:
print_diagnostic(PatientAge) :-
likelihood(Disease, PatientAge),
write('Increased likelihood of '), write(Disease), nl.

How to create predicate that is true if gets different values

I would like to ask how to create predicate that returns true if gets different values.
I have this database:
fruit(apple).
fruit(peach).
fruit(banana).
fruit(orange).
fruit(mandarine).
fruit(plum).
I need predicate threeFruits/3 that takes three fruits and says if they are different i.e.
threeFruits(apple,peach,banana). -> true
threeFruits(apple,apple,banana). -> false .. etc.
The code I have so far is not correct:
threeFruits(X,Y,Z):- fruit(X),fruit(Y),fruit(Z).
I tried also unification, but it can tell me only if they are same, but not working for different.
threeFruits(fruit(X),fruit(X),fruit(X)).
Thank you in advance for any hint.
Assuming the X, Y, Z are really atoms for which fruit/1 is valid, you can test whether they pairwise "do not unify" by using the negation of =/2 (i.e. the negation of unification)
threeFruits(X,Y,Z) :-
assertion(fruit(X)),
assertion(fruit(Y)),
assertion(fruit(Z)),
X\=Y,Y\=Z,X\=Z.
Alternatively, you can use the negation of ==/2 to check whether they pairwise "are not the same":
threeFruits(X,Y,Z) :-
assertion(fruit(X)),
assertion(fruit(Y)),
assertion(fruit(Z)),
X\==Y,Y\==Z,X\==Z.

Learn Prolog now: Why answering true to the first query of exercise 1.5?

I have just started learning Prolog, and I'm wondering about the first question of this exercise.
%% Suppose we are working with the following knowledge base:
wizard(ron).
hasWand(harry).
quidditchPlayer(harry).
wizard(X) :- hasBroom(X), hasWand(X).
hasBroom(X) :- quidditchPlayer(X).
How does Prolog respond to the following queries?
wizard(ron). -> true
witch(ron). -> undefined procedure
wizard(hermione). -> false
witch(hermione). -> undefined procedure
wizard(harry). -> true
wizard(Y). -> Y = ron ; Y = harry.
witch(Y). -> undefined procedure
Using swipl on Ubuntu, importing the knowledge base for this exercise, first of course trying to decipher what Prolog will returns, and finally checking by myself.
Ok pretty boring stuff until now, I have seen a few answer to these exercises over Github (here, here and there), and I don't understand the answer to the first one: %% 1. wizard(ron). -> true.
First of all the interpreter is complaining about the two definition of what is a wizard:
Warning: /tmp/prolog/ex15.pl:4:
Clauses of wizard/1 are not together in the source-file
Earlier definition at /tmp/prolog/ex15.pl:1
Current predicate: quidditchPlayer/1
Use :- discontiguous wizard/1. to suppress this message
Secondly, when querying I obtain:
?- wizard(ron).
true ;
false.
The way I get it, first Prolog returns the first fact from the knowledge base, then apply the rule head and find out that ron has neither a broom nor a wand.
All this leading to my question: what subtlety have I missed that makes others writing true as an answer to this query?
what subtlety have I missed that makes others writing true as an answer to this query?
`?- wizard(ron).`
true;
false
You have the clause (fact) wizard(ron). in your KB.
To make the things clearer you can write the fact also as the rule clause:
wizard(ron) :- true.
As you can see this is pretty redundant notation but useful in some cases as the general fact representation.
So your query can be interpreted as follows:
Is there an wizard called ron?
Since you have the fact wizard(ron) :- true.
Prolog will first unify the goal and the head.
In your case unify is trivial comparison because no variables are in the goal and the head.
Then Prolog tries to prove body. The body is builtin predicate true, so you quickly get the answer - true.
Then pressing ';' you initiate the search for the alternative solution.
Since no (more) solutions exist for the query wizard(ron), Prolog writes false.
The dot operator designates the clause end. So you wrongly typed dots in your examples:
-> operator means if-then-else relation. It can be used within clause body.
For example you can write std_member/2 as if_member/2
std_member(X, [ X | _ ]).
std_member(X, [ _ | Xs ]) :-
std_member(X, [ _ | Xs).
if_member(X, [ Y | Xs ]) :-
X = Y -> true;
if_member( X, Xs ).

Success and failure when querying the database

So I'm stuck on an exercise that I've been working on. I have the following facts:
sd(appleseed0, appleseed1).
sd(appleseed0, apple1).
sd(appleseed1, apple1).
sd(appleseed2, apple1).
sd(appleseed0, apple2).
sd(appleseed1, apple2).
sd(appleseed2, apple2).
What this means is that appleseed1 came from appleseed0, apple1 came from appleseed0, etc. The problem I'm having is that I need it to print out false if the values are switched around. Meaning, I want the query to result in "true" when the query is seed(appleseed0, apple1) and then "false" when the query is in opposite order like seed(apple1, appleseed0).
Right now, my predicate looks like this:
seed(A,B) :- sd(A,B) ; sd(B,A).
I understand that this is why my queries are returning true, no matter the order, but my only other idea is:
seed(A,B) :- sd(A,B).
but I cannot write it like that because that would make it an infinite loop with no false. How can I make it so that the query will result in "true" when shown with something like seed(appleseed2, apple2) and "false" when shown with something like seed(apple2, appleseed2)?
Hoping that I am reading your question correctly:
You don't need an extra predicate. Indeed, what you are looking for is the query:
?- sd(A, B).
This will succeed or fail just like you describe. The predicate
seed(A, B) :-
( sd(A, B)
; sd(B, A)
).
(just like yours, just formatted to be easier to follow) reads: "seed(A, B) is true when sd(A, B) is true. It is also true when sd(B, A) is true" (like you have noticed). An interesting side effect is that if you had these two facts in your database:
sd(foo, bar).
sd(bar, foo).
Then the query:
?- seed(foo, bar).
will succeed twice (!), just like the query
?- seed(bar, foo).
or the equivalent top level query
?- sd(bar, foo) ; sd(foo, bar).
That last query makes it most obvious why the query will succeed twice.
What confuses me: Why do you think that
seed(A, B) :-
sd(A, B).
will lead to an infinite loop? Is there some part of the program that you are not showing? As it stands, defining a predicate like this is equivalent to just giving sd/2 an alias, seed/2. This definition reads: "seed(A, B) is true when sd(A, B) is true."

Parse To Prolog Variables Using DCG

I want to parse a logical expression using DCG in Prolog.
The logical terms are represented as lists e.g. ['x','&&','y'] for x ∧ y the result should be the parse tree and(X,Y) (were X and Y are unassigned Prolog variables).
I implemented it and everything works as expected but I have one problem:
I can't figure out how to parse the variable 'x' and 'y' to get real Prolog variables X and Y for the later assignment of truth values.
I tried the following rule variations:
v(X) --> [X].:
This doesn't work of course, it only returns and('x','y').
But can I maybe uniformly replace the logical variables in this term with Prolog variables? I know of the predicate term_to_atom (which is proposed as a solution for a similar problem) but I don't think it can be used here to achieve the desired result.
v(Y) --> [X], {nonvar(Y)}.:
This does return an unbound variable but of course a new one every time even if the logical variable ('x','y',...) was already in the term so
['X','&&','X'] gets evaluated to and(X,Y) which is not the desired result, either.
Is there any elegant or idiomatic solution to this problem?
Many thanks in advance!
EDIT:
The background to this question is that I'm trying to implement the DPLL-algorithm in Prolog. I thought it would by clever to directly parse the logical term to a Prolog-term to make easy use of the Prolog backtracking facility:
Input: some logical term, e.g T = [x,'&&',y]
Term after parsing: [G_123,'&&',G_456] (now featuring "real" Prolog variables)
Assign a value from { boolean(t), boolean(f) } to the first unbound variable in T.
simplify the term.
... repeat or backtrack until a assignment v is found so that v(T) = t or the search space is depleted.
I'm pretty new to Prolog and honestly couldn't figure out a better approach. I'm very interested in better alternatives! (So I'm kinda half-shure that this is what I want ;-) and thank you very much for your support so far ...)
You want to associate ground terms like x (no need to write 'x') with uninstantiated variables. Certainly that does not constitute a pure relation. So it is not that clear to me that you actually want this.
And where do you get the list [x, &&, x] in the first place? You probably have some kind of tokenizer. If possible, try to associate variable names to variables prior to the actual parsing. If you insist to perform that association during parsing you will have to thread a pair of variables throughout your entire grammar. That is, instead of a clean grammar like
power(P) --> factor(F), power_r(F, P).
you will now have to write
power(P, D0,D) --> factor(F, D0,D1), power_r(F, P, D1,D).
% ^^^^ ^^^^^ ^^^^
since you are introducing context into an otherwise context free grammar.
When parsing Prolog text, the same problem occurs. The association between a variable name and a concrete variable is already established during tokenizing. The actual parser does not have to deal with it.
There are essentially two ways to perform this during tokenization:
1mo collect all occurrences Name=Variable in a list and unify them later:
v(N-V, [N-V|D],D) --> [N], {maybesometest(N)}.
unify_nvs(NVs) :-
keysort(NVs, NVs2),
uniq(NVs2).
uniq([]).
uniq([NV|NVs]) :-
head_eq(NVs, NV).
uniq(NVs).
head_eq([], _).
head_eq([N-V|_],N-V).
head_eq([N1-_|_],N2-_) :-
dif(N1,N2).
2do use some explicit dictionary to merge them early on.
Somewhat related is this question.
Not sure if you really want to do what you asked. You might do it by keeping a list of variable associations so that you would know when to reuse a variable and when to use a fresh one.
This is an example of a greedy descent parser which would parse expressions with && and ||:
parse(Exp, Bindings, NBindings)-->
parseLeaf(LExp, Bindings, MBindings),
parse_cont(Exp, LExp, MBindings, NBindings).
parse_cont(Exp, LExp, Bindings, NBindings)-->
parse_op(Op, LExp, RExp),
{!},
parseLeaf(RExp, Bindings, MBindings),
parse_cont(Exp, Op, MBindings, NBindings).
parse_cont(Exp, Exp, Bindings, Bindings)-->[].
parse_op(and(LExp, RExp), LExp, RExp)--> ['&&'].
parse_op(or(LExp, RExp), LExp, RExp)--> ['||'].
parseLeaf(Y, Bindings, NBindings)-->
[X],
{
(member(bind(X, Var), Bindings)-> Y-NBindings=Var-Bindings ; Y-NBindings=Var-[bind(X, Var)|Bindings])
}.
It parses the expression and returns also the variable bindings.
Sample outputs:
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y']).
Exp = and(_G683, _G696),
Bindings = [bind(y, _G696), bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'x']).
Exp = and(_G683, _G683),
Bindings = [bind(x, _G683)].
?- phrase(parse(Exp, [], Bindings), ['x', '&&', 'y', '&&', 'x', '||', 'z']).
Exp = or(and(and(_G839, _G852), _G839), _G879),
Bindings = [bind(z, _G879), bind(y, _G852), bind(x, _G839)].

Resources