Below are the codes I came up with. However, there are two problems here.
First, only first value of X is displayed which is 1. Second, if Y is false, it doesn't jump back to menu1.
Hope to get some help in this.
time(office_hour,1).
time(office_hour,2).
menu1 :-
write('Input time'),nl,
read(Y),nl,time(Y,X),nl,write(X),nl,menu1.
This is the example of the scenario. As seen below, only value 1 is shown. How to display value 2 too? Sry I'm just a newbie
?-menu1.
Input time
office_hour.
1.
Input time
You need to allow Prolog to backtrack to get all of the solutions. The problem with your predicate is that it does a recursive call before it can backtrack. Also, you continue to recurse one level deeper for the next menu prompt which is probably not good practice since it continually consumes more stack as it responds to user inputs.
Here's another approach, using the repeat/0 predicate along with fail/0. repeat/0 simply succeeds which allows to re-query for solutions during backtracking. And fail/0 always fails, which forces backtracking. It's a common way to do a continual repeat loop and works well for looping on a menu. I've also adjusted the nl/0 usage a bit to make the output a little neater, and I renamed time/2 since it is just too generic a name and could potentially collide with a system predicate.
item_time(office_hour,1).
item_time(office_hour,2).
menu1 :-
repeat,
nl, write('Input time'), nl,
read(Y),
item_time(Y, X),
write(X), nl,
fail.
This will yield:
| ?- menu1.
Input time
office_hour.
1
2
Input time
foo.
Input time
...
What happens here is that fail/0 will cause the predicate clause to backtrack through the write(X), nl and to the time(Y, X) which will come up with the alternate solutions, succeed on those solutions, and then move forward to the write(X), nl again. If time(Y, X) finds no more solutions, then it finally fails and the clause backtracks all the way back to the repeat/0 call, which always succeeds. That results in the execution moving forward again to the nl, write('Input time'), ....
As you can see, inputting something unrecognized just re-prompts. To make this more complete, you could add atoms that are recognized as a "quite" and you could write a diagnostic message if you get input that doesn't exist in your database. That would be a good exercise for learning.
The second problem:
menu1 :-
write('Input time'),nl,
read(Y),nl,
( time(Y,X) ->
write(X),nl
; write('bad input'),nl ),
menu1.
Related
Looking at the code below:
multiple(X,0).
multiple(X,Y) :- lt(0,X), lt(0,Y), diff(Y,X,D), multiple(X,D).
There happens to be something wrong. For your reference:
lt/2 is whether the first argument is less than the second.
diff/3 is whether the third argument is equal to the first argument minus the second.
lt/2 and diff/3 are defined correctly.
Is there a logical mistake in the definition? Is assuming that 0 is the multiple of every number problematic or is the logical mistake somewhere else? I get correct answers but the query goes to infinite loop I think.
EDIT:
here are the other definitions.
natNum(0).
natNum(s(X)) :- natNum(X).
lt(0,s(X)) :- natNum(X).
lt(s(X),s(Y)) :- lt(X,Y).
sum(0,X,X).
sum(s(X),Y,s(Z)) :- sum(X,Y,Z).
diff(X,Y,Z) :- sum(Z,Y,X).
?- multiple(X, s(s(s(s(s(s(0))))))).
where s(0) is 1, s(s(0)) is 2 etc. It gives all the desired answers for X but after the last answer, it gets stuck. I assume in an infinite recursive loop?
What is happening in your program? Does it loop forever, or does it only take some time since you haven't updated your hardware in recent decades? We cannot tell. (Actually, we could tell by looking at your program, but that is much too complex for the moment).
What we can do with ease is narrow down the source of this costly effort. And this, without a deep understanding of your program. Let's start with the query:
?- multiple(X, s(s(s(s(s(s(0))))))).
X = s(0)
; X = s(s(0))
; X = s(s(s(0)))
; X = s(s(s(s(s(s(0))))))
; loops. % or takes too long
Isn't there an easier way to do this? All this semicolon typing. Instead, simply add false to your query. In this manner the solutions found are no longer shown and we can concentrate on this annoying looping. And, if we're at it, you can also add false goals into your program! By such goals the number of inferences might be reduced (or stays the same). And if the resulting fragment (called a failure-slice) is looping, then this is a reason why your original program loops:
multiple(_X,0) :- false.
multiple(X,Y) :- lt(0,X), false, lt(0,Y), diff(Y,X,D), multiple(X,D).
natNum(0) :- false.
natNum(s(X)) :- natNum(X), false.
lt(0,s(X)) :- natNum(X), false.
lt(s(X),s(Y)) :- false, lt(X,Y).
?- multiple(X, s(s(s(s(s(s(0))))))), false.
loops.
Do your recognize your program? Only those parts remained that are needed for a loop. And, actually in this case, we have an infinite loop.
To fix this, we need to modify something in the remaining, visible part. I'd go for lt/2 whose first clause can be generalized to lt(0, s(_)).
But wait! Why is it OK to generalize away the requirement that we have a natural number? Look at the fact multiple(X,0). which you have written. You have not demanded that X is a natural number either. This kind of over-generalizations often appears in Prolog programs. They improve termination properties at a relatively low price: Sometimes they are too general but all terms that additionally fit into the generalization are not natural numbers. They are terms like any or [a,b,c], so if they appear somewhere you know that they do not belong to the solutions.
So the idea was to put false goals into your program such that the resulting program (failure-slice) still loops. In the worst case you put false at a wrong place and the program terminates. By trial-and-error you get a minimal failure-slice. All those things that are now stroked through are irrelevant! In particular diff/3. So no need to understand it (for the moment). It suffices to look at the remaining program.
I'm taking a crack at Prolog (using SWI-Prolog) and everything works like I want it to, i.e., the logic is calculated correctly and it finds the right solutions but the whole backtracking thing is screwing with me.
Here's the code:
tall(X) :- skinny(X) ; eatless(X).
eatless(X) :- playsmore(X).
playsmore(X) :- hasxbox(X) ; hasplaystation(X).
skinny(a).
vegetarian(a).
hasxbox(b).
eatsburger(c).
hasplaystation(d).
list_all_tall :- forall(tall(Tall), writeln(Tall)).
Very basic stuff. Here's what I get as a result of my queries:
?- tall(a).
true ; % Note 1
false.
?- tall(b).
true ; % Note 2
false.
?- tall(c).
false.
?- tall(d).
true.
As you can see from Notes 1 and 2, it waits for me to hit ; to move on and then considers the first solution as null and eventually outputs false.
I can use cuts to control this behavior better but I also want the following commands to work properly:
?- tall(X).
X = a ;
X = b ;
X = d.
And:
?- list_all_tall.
a
b
d
true.
These two commands give the solution exactly the way I want. Its just the ones for Notes 1 and 2 that are driving me up the wall. Is there a way that I can keep the functionality as it is right now for tall(X). and list_all_tall., while fixing the functionality of tall(a). and tall(b). to my liking, i.e., the program should exit with a true. after I ask tall(a). or tall(b).
I'd appreciated it if instead of giving straight answers someone could actually explain how I could go about fixing it myself because maybe my way of thinking in Prolog is all bassackwards.
PS: No offense intended to tall, skinny, fat, burger eating, video game playing, vegetarian folks.
Just to supplement Daniel's well-explained answer (+1) for your specific case, consider:
tall(a).
Prolog will look at the first match, which is through:
tall(X) :- skinny(X) ; eatless(X).
This will succeed because skinny(a) will succeed. However, there's a disjunction ; leaving a choice point for Prolog that it hasn't explored yet. Because skinny(a) succeeds and the choice point is pending, you get true but prompted to seek more. Prolog then backtracks to the choice point and tries to satisfy eatless(a) but fails. Thus, you get:
?- tall(a).
true ; % because `skinny(a)` succeeded
false. % because `eatless(a)` failed
Taking another example:
tall(d).
Again, this matches the tall/1 predicate, but this time, skinny(d) fails and prolog moves right on (due to the disjunction) to eatless(d) which succeeds. However, there are no more choice points after that success, so you get:
?- tall(d).
true. % There were no choice points available after success
The best thing to do is not worry about it, because you're not always going to be able to prevent it.
Prolog doesn't ever know that there will be another answer. It just knows that there may be another answer. This is called a choice point. Whenever Prolog reaches an alternative, it creates a choice point and then follows the first option. If that option doesn't work out, it backs up to the most recent choice point and tries the next alternative. If it runs out of alternatives without finding an answer, you get no or false.
You can try to write your code so that you don't get a choice point if you know there are no more items. member/2, for instance, in some Prologs you get false after the last item and in others you do not. But it isn't a composition problem to have a dud choice point after all your solutions. Your user interface probably won't show users Prolog's prompts directly. You can use setof/3 and the other extralogical predicates to get all the solutions. The false won't "leak" out into the world. It's a little unnerving at first, but just trust it and don't worry too much about it.
It is possible to run the same predicate, tall/1 in this case, in different modes based on different instantiation patterns.
When you run ?- tall(a). you instantiate the argument (i.e., X=a) and you want to receive either true or false (and no choicepoints, indicated by ;).
In Prolog this mode is called semi-deterministic.
You can force your predicate to be semi-deterministic for this specific instantiation pattern in the following way:
tall(X):- (ground(X) -> once(tall0(X)) ; tall0(X)).
Here ground(X) succeeds just in case X is fully instantiated.
Fully instantiated means that it is not a variable nor is it a compound term containing a variable.
tall0(X) is your original predicate.
The second mode you want to use is ?- tall(X).
Here you expect all results to be given subsequently, using ;.
This mode is called non-deterministic in Prolog.
The complete code for your example is:
tall(X):- (ground(X) -> once(tall0(X)) ; tall0(X)).
tall0(X):- skinny(X) ; eatless(X).
eatless(X):- playsmore(X).
playsmore(X):- hasxbox(X) ; hasplaystation(X).
skinny(a).
hasxbox(b).
hasplaystation(d).
Now the single predicate tall/1 can be called in the two modes, producing the behavior you want. Semi-deterministic usage:
?- tall(a).
true.
Non-deterministic usage:
?- tall(X).
X = a ;
X = b ;
X = d.
Hope this helps!
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
Mr Boddy was having an affair with Ms. Green.
Professor Plum is married to Ms. Green.
Mr. Boddy was very rich.
Colonel Mustard is very greedy.
Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect.
Clearly indicate this line in your source comments so that it can be removed/added for
grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false into your program. I will add as many false goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.
married(profPlum, msGreen) :- false.
married(X,Y) :- married(X,Y), false, married(Y,X).
hate(X,Y) :- married(X,Spouse), false, affair(Y,Spouse).
suspect(X,Y):- hate(X,Y), false.
suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :- as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided X is married to Y and Y is married to X
we can conclude that
X is married to Y.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen) holds but married(msGreen, profPlum) does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2 and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1 or (\+)/1 must not appear in the fragment.
2 This example is of interest to #larsmans.
The problem is the recursive rules of the predicates affair/2 and married/2. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2 predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.
I can't figure out where this is going wrong. Please note that I am very new to Prolog and I'm sure I'm missing something - just no idea what that might be. Could anyone help me out please?
Thanks, here is my code:
printSentence([]).
printSentence([W|[]]) :-
write(W),
write('.'),
nl.
printSentence([W|R]) :-
write(W),
write(' '),
printSentence(R).
transform([], Result).
transform([Word|Rest], Result) :-
replace(Word, Replacement),
append(Result, Replacement, NewResult),
transform(Rest, NewResult).
replace(my, your).
replace(i, you).
replace(you, me).
replace(am, are).
replace(Word, Word).
test :-
X = [you, are, my, only, hope],
transform(X, Result),
printSentence(Result).
#Junuxx' answer is one step to the solution ; there is also another problem in your program. But first step back: #Junuxx spotted the problem and fixed it. Nice. But how can you spot such a problem? Actually, you asked »infinite loop – but how?«
What is cool in Prolog is that you can often localize the looping program up to a very tiny fragment of the program. Such a fragment is called a failure-slice. That is: No more eye-sores reading lengthy programs!
Let's get back to your program. If you load it, you will get a message like:
Warning: /usager/SO/paranoid.pl:13:
Singleton variables: [Result]
Which gives you already a hint on something most probably wrong. Alas, this is not your biggest concern for the moment. Your biggest problem is that the goal test loops!
Localizing non-termination
So how can you with low effort realize what is actually looping?
One way would be to fire up a tracer, which will show you step-by-step how Prolog executes this program. However, the tracer will show you a lot of irrelevant detail. Detail, that you do not need to understand when programming in Prolog. Detail, that fills up your mind such that chances are that you will miss the actual problem completely. So unless you want to spend time on screens full with flickering lines, stay away from tracers.
The other way is to add goals false into your program. Remember, your program loops already, so such extra goals will not hurt you much. Why vandalize your program with these false goals that you never wanted to write in the first place? It's because these false goals will help you detect the culprit of non-termination in your program by hiding "irrelevant" parts. This is so, thanks to the following observation:
If a failure-slice (= your vandalized program) does not terminate then the original program does not terminate either.
In a sense, the failure-slice is a reason why your program does not terminate. Or to put it more strongly: As long as you do not change the visible part in a failure-slice ; that is, as long as you are only trying your luck by modifying parts that are not visible in the failure slice, the problem will persist! Guaranteed! That is not the nicest kind of guarantee but it is better than being blind.
Here is what I get as a failure slice. I removed printSentence/1 because it is no longer used in the fragment. And I added the definition of append/3. Some Prologs offer append/3 as a built-in predicate that you cannot modify. In that case use another name, like local_append/3 – just don't forget to replace all occurrences!
append([], Zs, Zs) :- false.
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs), false.
transform([], Result) :- false.
transform([Word|Rest], Result) :-
replace(Word, Replacement),
append(Result, Replacement, NewResult), false,
transform(Rest, NewResult).
replace(my, your) :- false.
replace(i, you) :- false.
replace(you, me).
replace(am, are) :- false.
replace(Word, Word) :- false.
test :-
X = [you, are, my, only, hope],
transform(X, Result), false,
printSentence(Result).
When I load this failure-slice, I get:
?- test.
ERROR: Out of local stack
Which is a good indication that the program does not terminate. On my finite hardware it exhausts all resources instead. ((To be pedantic, this program might still terminate, it might only need too much resources. But remember: We have this if failure-slice loops, then the entire program loops. In any case, proving non-termination of the failure-slice will often be easier, since the fragment is shorter)).
Some observations: Originally, transform/2 used to be recursive. Now, it no longer is. The only recursion left is within append/3. So I first look at the goal append(Result, Replacement, NewResult) and I try to figure out what the variables might be. The easiest is the 3rd argument: NewResult is the only occurrence in our fragment, we can thus replace it by _. The second argument's variable Replacement will always be me. And the first argument (here I have now to look at test/0) will be an uninstantiated variable. So we have to consider the goal append(_, me, _).
Simply run append(_, me, _), false to see that this goal does not terminate! You can see this also by inspecting the failure-slice. Here is it, again:
append([], Zs, Zs) :- false.
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs), false.
Look at Ys: Nobody cares about it, it is just "handed over". Only the first and the third argument might guarantee termination!
For more see the tag failure-slice.
Fine print
Certain restrictions apply! Void where prohibited! You can do above reasoning only with a pure, monotonic Prolog program. Actually, some benign side-effects as the ones you have in your program are OK too. As long as they do not affect the control-flow.
The other problem
There is another problem with your program. Run printSentence([you]), false to see it! Backtracking and side-effects do not flock together easily. For a beginner, the best is to avoid side-effects all together. See this question and that answer for an example, how to remove useless side-effects in programming problems.
Why not call transform([you, are, my, only hope], Xs) or maplist(replace,[you, are, my only, hope], Xs) directly? It lets you again concentrate on the relevant parts!
This should work. Notice you had a singleton in transform([],Result). Also, append doesn't work in the way you tried to use it, but you were on the right track generally.
transform([], []).
transform([Word|Rest], [Replacement|RestOfResult]) :-
replace(Word, Replacement),
transform(Rest, RestOfResult).
I can't come up with a situation where I would need it.
Elegant systems provide false/0 as a declarative synonym for the imperative fail/0. An example where it is useful is when you manually want to force backtracking for side-effects, like:
?- between(1,3,N), format("line ~w\n", [N]), false.
line 1
line 2
line 3
Instead of false/0, you can also use any goal that fails, for example a bit shorter:
?- between(1,3,N), format("line ~w\n", [N]), 0=1.
line 1
line 2
line 3
Thus, false/0 is not strictly needed but quite nice.
EDIT: I sometimes see beginners who want to state for example "my relation does not hold for the empty list", and then add:
my_relation([]) :- false.
to their code. This is not necessary, and not a good example of using false/0, except for example in failure slices that are programmatically generated. Instead, concentrate on stating the things that hold about your relation. In this case, just leave out the entire clause, and define the relation only for lists that are not empty, i.e., have at least one element:
my_relation([L|Ls]) :- etc.
or, if you are describing other terms in addition to lists as well, use a constraint like:
my_relation(T) :- dif(T, []), etc.
Given only either (or even both) of these two clauses, the query ?- my_relation([]). will automatically fail. It is not necessary to introduce an additional clause which never succeeds for that purpose.
Explicit failure. fail is often used in conjunction with cut: ... !, fail. to enforce failure.
For all construct. Explicit usage of fail/false to enumerate via backtracking is a very error prone activity. Consider a case:
... ( generator(X), action(X), fail ; true ), ...
The idea is thus to "do" action for all X. But what happens, if action(X) fails? This construct simply continues with the next candidate — as if nothing happened. In this manner certain errors may remain undetected for very long.
For such cases it is better to use \+ ( generator(X), \+ action(X) ) which fails, should action(X) fail for some X. Some systems offer this as a built-in forall/2. Personally, I prefer to use \+ in this case because the \+ is a bit clearer that the construct does not leave a binding.
Failure-slice. For diagnostic purposes it is often useful to add on purpose false into your programs. See failure-slice for more details.
One case (taken from Constraint Logic Programming using Eclipse) is an implementation of not/1:
:- op(900, fy, not).
not Q :- Q, !, fail.
not _ .
If Q succeeds, the cut (!) causes the second not clause to be discarded, and the fail ensures a negative result. If Q fails, then the second not clause fires first.
Another use for fail is to force backtracking through alternatives when using predicates with side effects:
writeall(X) :- member(A,X), write(A), fail.
writeall(_).
Some people might not consider this particularly good programming style though. :)
fail/0 is a special symbol that will immediately fail when prolog encounters it as a goal.
fail is often used in conjunction with CUT(!) to enforce failure.
like(me,X) :- chess(X),!,fail.
like(me,X) :- games(X).