Reputation: 768
I follow the book Problem solving with Prolog by John Stobo. I've studied the Chapter 1 (Programming with Facts) and Chapter 2 (Programming with Rules) Now I am at Chapter 3: Recursion in Rules and I'm practicing the program given in the Section 3.1. I've elobarated the program a bit (without changing the main structure) and added my own functor (or function or rule ?) named is_rank_lower/2
but it doesn't work as expected.
When I enter (or ask Prolog)
is_rank_lower(ryan, jondoe).
the output is
false.
the expected output: true.
Because ryan is a private and jondoe is a corporal and private is lower in rank than corporal.
The explanations are in the code.
Question #1: How to make my own functor is_lower_rank work as expected?
Question #2: This question might be related to the book because when I write down the program exactly as it is, it works slightly wrongly and that might be causing my own functor to function wrongly, too. Just a guess.
When I enter:
lower_rank(private, corporal).
Prolog returns with true
and waits at it, I have to put a dot after the true
and click enter only then does it return to the ?-
prompt.
The expected output is:
return with true.
then return to the ?-
prompt
The author seems to talk about this problem. In page 57 he writes "lower_rank would not terminae if the goal ought to fail" I've applied all the instructions but the functor still doesn't work. How to make it work?
My prolog version swi-prolog 7.2.0
% John Stobo, problem solving with Prolog, March.1989
% FACTS:
next_degree(private, corporal).
next_degree(corporal, sergeant).
next_degree(sergeant, lieutenant).
next_degree(lieutenant, captain).
next_degree(captain, major).
next_degree(major, "lieutenant colonel").
next_degree("lieutenant colonel", colonel).
next_degree(colonel, "brigadier general").
next_degree("brigadier general", "major general").
next_degree("major general","lieutenant general").
next_degree("lieutenant general", general).
soldier(ryan, private).
soldier(jondoe, corporal).
sooldier(smartson, captain).
% RULES:
lower_rank(R1, R2) :-
next_degree(R1, R2).
lower_rank(R1, R2) :- % this works but if
next_degree(R1, R3), % the result is "true"
lower_rank(R3, R2). % it doesn't end properly
% only if the user types a dot, it ends properly
is_rank_lower(A1,A2) :-
lower_rank(soldier(A1,X), soldier(A2,X)).
% doesn't work because the functors are inserted as
% 'soldier(ryan, _G1471), soldier(jondoe, _G1471))
% not as private, corporal, i.e. they are not evaluated
Upvotes: 0
Views: 142
Reputation: 4438
That next_degree/2 seems like a bizarre method - is the book suggesting it as sensible, or as an example of what not to do?
There are decent books at https://swi-prolog.discourse.group/t/useful-prolog-references/1089
This works:
% First argument is an atom, hence single quotes in swi-prolog
rank_order(private, 1).
rank_order(corporal, 2).
rank_order(sergeant, 3).
rank_order(lieutenant, 4).
rank_order(captain, 5).
rank_order(major, 6).
rank_order('lieutenant colonel', 7).
rank_order(colonel, 8).
rank_order('brigadier general', 9).
rank_order('major general', 10).
rank_order('lieutenant general', 11).
soldier(ryan, private).
soldier(jondoe, corporal).
% Not mis-spelled as "sooldier"
soldier(smartson, captain).
rank_lower(RankLower, RankUpper) :-
rank_order(RankLower, RankLowerOrder),
rank_order(RankUpper, RankUpperOrder),
RankLowerOrder < RankUpperOrder.
soldier_rank_lower(SoldierLower, SoldierUpper) :-
soldier(SoldierLower, RankLower),
soldier(SoldierUpper, RankUpper),
rank_lower(RankLower, RankUpper).
Results in swi-prolog:
?- rank_lower(private, corporal).
true.
?- soldier_rank_lower(ryan, jondoe).
true.
?- soldier_rank_lower(L, U).
L = ryan,
U = jondoe ;
L = ryan,
U = smartson ;
L = jondoe,
U = smartson ;
false.
2nd attempt:
rank_next(private, corporal).
rank_next(corporal, sergeant).
rank_next(sergeant, lieutenant).
rank_next(lieutenant, captain).
rank_next(captain, major).
rank_next(major, 'lieutenant colonel').
rank_next('lieutenant colonel', colonel).
rank_next(colonel, 'brigadier general').
rank_next('brigadier general', 'major general').
rank_next('major general', 'lieutenant general').
rank_next('lieutenant general', general).
soldier(ryan, private).
soldier(jondoe, corporal).
soldier(smartson, captain).
rank_lower(RankLower, RankUpper) :-
rank_next(RankLower, RankLower1),
% Increase lower to eventually meet with upper
( RankLower1 = RankUpper ;
rank_lower(RankLower1, RankUpper)
).
soldier_rank_lower(SoldierLower, SoldierUpper) :-
soldier(SoldierLower, RankLower),
soldier(SoldierUpper, RankUpper),
% Won't have multiple answers
once(rank_lower(RankLower, RankUpper)).
This makes the following deterministic:
?- soldier_rank_lower(ryan, jondoe).
true.
... whilst keeping the generality of rank_lower/2, i.e.:
?- findall(L-U, rank_lower(L, U), Pairs), length(Pairs, Len).
Pairs = [private-corporal,private-sergeant,private-lieutenant, ...
Len = 66.
Upvotes: 2