Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert if else to fully declarative in Prolog?

It's one of my classroom question.

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"?

like image 566
J.Doe Avatar asked Dec 31 '16 09:12

J.Doe


2 Answers

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 .
like image 68
CapelliC Avatar answered Sep 21 '22 00:09

CapelliC


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).
like image 36
Guy Coder Avatar answered Sep 17 '22 00:09

Guy Coder