what is a good way to link exclusive statements in prolog? - prolog

We were asked to write a menu based calculator on an exam where we were to return control to the menu once the desired calculation had been performed.
I wrote the following code as my solution and while the professor deemed it as correct I still think there must be a better way to return control to the menu after the the first clause to table(A,N) returns false.
Please note that I've redacted quite a bit of my original code that was irrelevant to my question.
menu :-
write('Enter a choice: '),
read(C),
choice(C).
choice(1) :-
table(5).
table(N) :-
A is 1,
start(A,N).
table(A,N) :-
K is A*N,
write(K),
nl,
A1 is A+1,
A1=<10,
table(A1, N)
;
menu.
I'm very new to prolog so the question might not be appropriately worded. Please let me know if that's the case.

You can use repeat/0 to loop forever.
menu :-
repeat, % add this line
write('Enter a choice: '),
read(C),
choice(C).
choice(1) :-
table(5).
table(N) :-
A is 1,
start(A,N).
table(A,N) :-
K is A*N,
write(K),
nl,
A1 is A+1,
A1=<10,
table(A1, N).
% ; % delete this line
% menu. % delete this line

Related

PROLOG family tree: how can I output all the siblings and cousins?

Hi I am working on a PROLOG family tree question, and this is what I have so far:
/*1. Write Prolog clauses to express the following three relationships,
* given the parent/2 relationship: grandparent/2, sibling/2, cousin/2.*/
% clauses
parent(jill, amy).
parent(jill, tim).
parent(jill, john).
parent(amy, grace).
parent(amy, anna).
parent(tim, sam).
parent(tim, joel).
parent(tim, ben).
% rules
grandparent(X,Y) :-
parent(Z,Y),
parent(X,Z).
sibling(X, Y) :-
parent(Z, X),
parent(Z, Y).
cousin(X,Y) :-
parent(P, X),
parent(S, Y),
sibling(P, S).
When I put:
?- sibling(X, tim).
the output gives:
X = amy
but both john and amy are tim's sibling. The same problem happens with:
?- cousin(ben, X).
which gives:
X = grace
when both grace and anna are ben's cousins.
What changes do I need to make in order for the code to output all of tim's siblings and ben's cousins?
Thanks. :)
First of all, you've got a little bug over there.
You should correct the sibling rule - just a small hint here, try to use the rule as so
sibling(grace,grace)
and back to your issue, after you're getting first response click the ; or any of these ; n r space TAB keys, as the result you see is the first correct response. If you want to see the next correct result you need to use one of the keys above.
You can also try to use findall predicate to see all the results in the list
?- findall(X, cousin(grace, X),Z).
Z = [sam, joel, ben].

Proof as an output argument in Prolog meta interpreter

I am putting together a simple meta interpreter which outputs the steps of a proof. I am having trouble with getting the proof steps as an output argument. My predicate explain1 returns the proof in the detailed form that i would like, but not as an output argument. My predicate explain2 returns the proof as an output argument but not with the level of detail that i would like. Can explain2 be modified so that it yields as much info as explain1? I don't need it to output text "Explaining..." and "Explanation...", just the actual explanans and explanandum.
The toy data at the bottom of the program ("if healthy and rich, then happy") is just an example and the idea is to have a database with more facts about other things. I want to try to make a predicate that accepts an effect, e.g. happy(john), and returns an explanation for it. So the E argument of explain is supposed to be entered by the user; another query might thus be explain(_, smokes(mary), _) and so on. I can't get what i want directly from the C and E variables in explain, because i want the program to output steps in the Proof process, where C and E vary, e.g. "rich and healthy, so happy; wins so rich; TRUE so rich; TRUE so happy" and so on. I.e. return all causal links that lead up to an effect.
The excellent site by Markus Triska has some details on this, but i am having trouble adapting that code to my problem.
Any help would be greatly appreciated!
Thanks/JCR
My program:
main1:-explain1(_, happy(john), _), fail.
main2:-explain2(_, happy(john), _, T), writeln(T), fail.
explain1(C, E, P):-
C = ['True'],
p(C, E, P),
write('Explaining '), write(E),
write('. An explanation is: '), write(C),
write(' with probability '), write(P), nl.
explain1(C, E, P):-
p(C, E, P),
not(C = ['True']),
write('Explaining '), write(E),
write('. An explanation is: '), write(C),
write(' with probability '), write(P), nl.
explain1(C, E, P):-
p(C0, E, P0),
maplist(explain1, C1, C0, P1),
flatten(C1, C),
append([P0], P1, P2),
flatten(P2, P3),
foldl(multiply, P3, 1, P),
write('Explaining '), write(E),
write('. An explanation is: '), write(C),
write(' with probability '), write(P), nl.
explain2(C, E, P, T):-
C = ['True'],
p(C, E, P),
T = [C, E, P].
explain2(C, E, P, T):-
p(C, E, P),
not(C = ['True']),
T = [C, E, P].
explain2(C, E, P, T):-
p(C0, E, P0),
maplist(explain2, C1, C0, P1, _),
flatten(C1, C),
append([P0], P1, P2),
flatten(P2, P3),
foldl(multiply, P3, 1, P),
T = [C, E, P].
multiply(V1, V2, R) :- R is V1 * V2.
p(['True'], wins(john), 0.7).
p([wins(john)], rich(john), 0.3).
p(['True'], healthy(john), 0.9).
p([rich(john), healthy(john)], happy(john), 0.6).
The output of main1:
Explaining happy(john). An explanation is: [rich(john), healthy(john)] with probability 0.6
Explaining rich(john). An explanation is: [wins(john)] with probability 0.3
Explaining healthy(john). An explanation is: [True] with probability 0.9
Explaining happy(john). An explanation is: [wins(john), True] with probability 0.162
Explaining wins(john). An explanation is: [True] with probability 0.7
Explaining rich(john). An explanation is: [True] with probability 0.21
Explaining healthy(john). An explanation is: [True] with probability 0.9
Explaining happy(john). An explanation is: [True, True] with probability 0.1134
The output of main2:
[[rich(john), healthy(john)], happy(john), 0.6]
[[wins(john), True], happy(john), 0.162]
[[True, True], happy(john), 0.1134]
I'm unclear on the probability portion of this metainterpreter, but I actually think it's incidental to your question so I'm going to try and sketch out how I would approach this.
You can think of call/1 as the prototypical interpreter for Prolog, because it simply proves a single goal. So it seems like the API you want is something like prove(+Goal, -Proof), where Goal gets proven just like it does with call/1, but you get a second thing back, a proof of some kind.
When normal Prolog sees an expression like Goal1, Goal2, you could think of it expanding into call(Goal1), call(Goal2). So what does your proof-returning metainterpreter do in this situation instead? It should prove both goals and then somehow combine those "subproofs".
All this suggests to me that something missing from your conception is, what is the structure of a proof? I would think hard about what kind of thing you're going to get back, because if you don't want a string, you'll want something you can traverse more easily. It will probably wind up having a tree structure similar to what Prolog does (except without the failure branches). I would thus expect it to have some kind of nesting and it could certainly "resemble" the call stack somehow, although I expect this would limit its utility for you (how are you going to traverse that tree usefully for a generic query?).
Let's consider your base case. It's probably something like this:
prove(true, true) :- !.
True is intrinsically true, because it is true.
The next case I would be interested in is "and".
prove((G1, G2), (P1, P2)) :-
!,
prove(G1, P1),
prove(G2, P2).
This looks fairly tautological, but the key idea really is that we are combining the proofs of G1 and G2 with (P1, P2) in the proof.
The next case would be "or" probably:
prove((G1;_), P1) :- prove(G1, P1).
prove((_;G2), P2) :- !, prove(G2, P2).
This is the part where we are losing the failing branches. If the first branch succeeds, its proof will appear in the result; if the second branch succeeds instead, its proof will appear in the result. But they won't ever both appear in the result.
Finally we must handle builtins and user predicates, per a question I asked some time ago:
prove(H, subproof(H, Subproof)) :- clause(H, Body), prove(Body, Subproof).
prove(H, builtin(H)) :- call(H).
At this point we have a metainterpreter that produces very simple proofs. I'm going to add a few clauses and then try it with our metainterpreter:
mortal(X) :- man(X).
man(socrates).
Here's the query:
?- prove((member(X, [bread,socrates]), mortal(X)), Proof).
X = socrates,
Proof = (builtin(member(socrates, [bread, socrates])),
subproof(mortal(socrates),
subproof(man(socrates), true)))
For reasons I do not yet understand, the use of member/2 will bomb out on a second query. I have opened a question about that on the SWI forum and will update this answer when I find out what's going on there.
Update. The issue is related to the autoloading of library(lists) which happens when you use member/2. On the first call, member/2 has no clauses, so it enters call/1, which invokes the autoloader and then invokes it as a built-in. On a subsequent attempt, member/2 has clauses, but their bodies involve predicates in the lists module, and this metainterpreter does not handle modules properly. A quick-and-dirty solution is to change the third clause to this:
prove(H, subproof(H, Subproof)) :-
\+ predicate_property(H, imported_from(_)),
clause(H, Body),
prove(Body, Subproof).
I hope this helps!

A Prolog rule that returns the subgoals in a proof search

I am looking for a simple/straightforward way to write a rule that outputs the antecedents in a proof search (successes of subgoals). Suppose i have the code
winsLottery(john).
healthy(john).
rich(X):-winsLottery(X).
happy(X):-rich(X), healthy(X).
I would like a rule antecedents(L, happy(john)), which returns
L = [
[rich(john), healthy(john)],
[winsLottery(john), healthy(john)]
]
I know about trace/0 but i am looking for a rule. I also tried clause/2 but this just gets the clause where the target event occurs and not any previous antecedents.
My motive is that I am interested in constructing a system that provides explanations for events. I know that i could do causes([rich(X), healthy(X)], happy(X)) in the knowledge base, but i am looking for clean and simple Prolog code that i can translate to classic first order logic (where lists are a bit problematic).
Thanks!
Looking at the suggestions of Guy, here is the solution:
main:-explain(happy(john)).
winsLottery(john).
healthy(john).
rich(X):-winsLottery(X).
happy(X):-rich(X), healthy(X).
explain(X):-
clause(X, B),
B == true.
explain((X1, X2)):-
explain(X1),
explain(X2).
explain(X):-
X \= true,
X \= (_, _),
clause(X, B),
write('An explanation for '), write(X), write(' is: '), nl, write(B), nl, nl,
explain(B).

How to print all facts?

I'm trying to print all facts in my Prolog problem. Have searched the forum for a while and can't seem to find a solution to the problem. I tried the how can I print all database facts in prolog but can't seem to make it work. Im doing a menu for it, so, when I press the corresponding key, it should show me all the facts and print back the menu. Something like this (its not complete):
if_then_else(P,Q,R):- P,!,Q.
if_then_else(P,Q,R):- R.
:- dynamic client/2.
client(john,password).
client(charles,bird).
printmenu:- write('1-Print all facts').
read(X),
if_then_else(X=1,printfacts,(error,printmenu)).
printfacts:-
Why not
printfacts :-
forall(client(X, Y),format('client(~w, ~w)~n', [X, Y])).
If you just want to print the facts (not return them all in a list or whatever), then:
printfacts :-
client(X, Y),
format('client(~w, ~w)~n', [X, Y]),
false.
printfacts.
Your printmenu could be written:
printmenu :-
repeat,
write('1-Print all facts').
read(X),
( X = 1
-> printfacts
; write('Invalid response'), nl,
),
fail. % Go back to the top and reprompt

Hanoi Tower(Towers of Hanoi)

I'm trying to do the Towers of Hanoi problem, what I have tried so far:
move(1,[H|T],B,C,A1,B1,C) :-
A1 = T,
B1 = [H|B].
move(N,A,B,C,A1,B1,C) :-
N>1,
M is N-1,
move(M,[H|T],C,B,A1,B1,C),
move(1,[H|T],B,_,A1,B1,C),
move(M,C,B,[H|T],A1,B1,C).
but this code does not work, I need get the result is looks like this:
?-move(3,[1,2,3],[],[],A1,B1,C).
and the results:
A1=[].
B1=[1,2,3]
C=[].
can someone help me fix my code up and can get the result like that? This is very important for me, I really need help.
this is what i did but with some problems:
move(N,[H|T],[],[],A1,B1,C) :-
N > 1,
M is N - 1,
move(N,[H|M],[H|_],[],A1,B1,C),
move(M,[_|M],[H|_],[H|_],A1,B1,C),
move(M,[_|M],[],[H|T],A1,B1,C),
move(M,[],[_|T],[H|T],A1,B1,C),
move(M,[H|_],[_|T],[H|T],A1,B1,C),
move(M,[H|_],[_|T],[],A1,B1,C),
move(M,[],[H|T],[],A1,B1,C).
move(N,[H|T],[],[]) :- write(A1), nl,
write(B1), nl,
write(C).
This is the instruction by instruction of solving towers of Hanoi problem.
move(1,X,Y,_) :-
write('Move top disk from '),
write(X),
write(' to '),
write(Y),
nl.
move(N,X,Y,Z) :-
N>1,
M is N-1,
move(M,X,Z,Y),
move(1,X,Y,_),
move(M,Z,Y,X).
Attack the problem in such a way: In the instruction by instruction solution we don't change the contents of X,Y or Z. But in your problem, you will eventually change the contents of them.
UPDATE:
Since it is declared that this is not a homework question, here is the full answer:
towersOfHanoi(N,A,B,C,A4,B4,C4) :- move(N,A,B,C,A4,B4,C4),!.
move(1,[H|T],B,C,A1,B1,C1) :- A1 = T,
B1 = [H|B],
C1 = C.
move(N,A,B,C,A4,B4,C4) :- N>1,
M is N-1,
move(M,A,C,B,A1,C1,B1),
move(1,A1,B1,C1,A2,B2,C2),
move(M,C2,B2,A2,C4,B4,A4).

Resources