It's one of my classroom question.
I was able to create my own Prolog program with bunch of if-else but I was told that my program is not fully declarative as its one of the very foundation principle in Prolog.
Here's my code
%start with :- go.
is_spicy :-
write('Do you want spicy? (yes/no)'),
read(Preference),
( Preference == yes -> recommend("Curry"); recommend("Kurma") ).
is_fry :-
write('Do you want fry food? (yes/no)'),
read(Preference),
( Preference == yes -> recommend("StirFry"); recommend("Chicken") ).
is_chili :-
write('Do you want chili? (yes/no)'),
read(Preference),
( Preference == yes -> recommend("Sambal"); recommend("Singgang") ).
recommend(Food) :- write('We recommend you '), write(Food).
go :-
write('Which food type do you prefer? (indian, chinese, malay): '),
read(FoodType),
(
FoodType == indian -> is_spicy;
FoodType == chinese -> is_fry;
FoodType == malay -> is_chili;
writeln('Please try again')
).
Anyone has any idea on how to make it "fully declarative"?
If you address the redundancy in your code, factoring out data from logic, you end with much more declarative code.
So, encode the data structure, and provide an 'interpreter' able to ask questions and infer the consequences.
For instance
dt(food_type,
[indian -> dt(spicy, [ y -> curry, n -> curma ])
,chinese -> dt(fry, [ y -> stirFry, n -> chicken ])
,malay -> dt(chili, [ y -> sambal, n -> singgang ])
]).
interpreter(dt(About, Choices), Choice) :-
% present a menu for choices
% recurse on selected path
% when it reach a leaf, just unify
interpreter(Choice, Choice).
you may want to specialize the menu for y/n only choices, but it's up to you
edit
Presenting a menu and accepting choices require extra logical programming, for instance:
solve(Choice) :-
dt(About, Choices),
interpreter(dt(About, Choices), Choice).
% present a menu for choices
% recurse on selected path
interpreter(dt(About, Choices), Choice) :-
ask_user(About, Choices, ChoiceAbout),
interpreter(ChoiceAbout, Choice).
% when it reach a leaf, just unify
interpreter(Choice, Choice).
ask_user(About, Choices, Choice) :-
format('your choice about ~w ?~n', [About]), % show user the context of choice
forall(member(C->_,Choices), format(' ~w~n', [C])),
read(U),
memberchk(U->Choice, Choices).
% note: if memberchk above fails (user doesn't input a correct choice)
% you should provide an alternate ask_user here, otherwise ...
% just see what the code does
%
Example session:
% /home/carlo/Desktop/pl/choices compiled into choices 0.00 sec, 0 clauses
?- solve(C).
your choice about food_type ?
indian
chinese
malay
|: chinese.
your choice about fry ?
y
n
|: n.
C = chicken .
CapelliC gave an answer that was more refined, which I like because I also learned some from his answer.
Here is a simpler version that should help connect the dots.
The trick was to think about the desired end result as a set of individual rules, e.g. food(indian,spicy)
and then how to get to them. Once I changed the answers from yes/no to the values for the variables the rest was down hill. Obviously yes/no can be used, but that just needs additional coding.
food(indian) :-
write('Do you want spicy? (spicy/not_spicy)'),
read(Preference),
food(indian,Preference).
food(chinese) :-
write('Do you want fry food? (fry/not_fry)'),
read(Preference),
food(chinese,Preference).
food(malay) :-
write('Do you want chili? (chili/not_chili)'),
read(Preference),
food(malay,Preference).
food(indian,spicy) :- recommend("Curry").
food(indian,not_spicy) :- recommend("Kurma").
food(chinese,fry) :- recommend("StirFry").
food(chinese,not_fry) :- recommend("Chicken").
food(malay,chili) :- recommend("Sambal").
food(malay,not_chili) :- recommend("Singgang").
recommend(Food) :- write('We recommend you '), write(Food).
go :-
write('Which food type do you prefer? (indian, chinese, malay): '),
read(FoodType),
food(FoodType).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With