Пролог: как проверить пользовательский ввод? - PullRequest
0 голосов
/ 06 марта 2020

Я новичок в Прологе и пытаюсь реализовать пример из учебника. В конце концов я смог заставить пример работать (благодаря определенной помощи из предыдущих сообщений о переполнении стека!), Но теперь он просит меня проверить ввод пользователя: «Измените данную программу дерева решений, чтобы, когда пользователь реагировал на вопрос с неправильным ответом, система попросит его / ее повторно ввести ответ, который входит в число указанных вариантов. "

В приведенной ниже программе для семейного положения указаны только указанные варианты, рассматриваемые в дереве решений. "холостой или женатый." Если вы введете что-то еще, цель состоит в том, чтобы заставить вас повторно принять решение.

Это не работает для меня. Мой код ниже:

:-dynamic income/2.
:-dynamic marital_status/2.
:-dynamic mortgage/2.
:-dynamic age/2.

marital_status(joe,married).
income(joe,60000).
mortgage(joe,20000).
age(joe,45).

main(X,Z):-var(X), write('what is your name?'),read(X), invest(X,Z),!.
main(X,Z):-invest(X,Z),!.
ask_marital_status(X,Y):-marital_status(X,Y).
ask_marital_status(X,Y):-not(marital_status(X,Y)), write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
ask_marital_status(X,Y):-Y \=married, Y \=single, write('what is your marital status: married or single?'), read(Y), nl, asserta(marital_status(X,Y)).
%ask_marital_status(X,Y):-Y \= married; Y \= single, ask_marital_status(X,Y).
ask_income(X,Y):-income(X,Y).
ask_income(X,Y):-not(income(X,Y)),write('what is your annual income?'), nl, read(Y), asserta(income(X,Y)).
ask_mortgage(X,Z):-mortgage(X,Z).
ask_mortgage(X,Z):-not(mortgage(X,Z)), write('what is your mortgage?'), read(Z), nl, asserta(mortgage(X,Z)).
ask_age(X,A):-age(X,A).
ask_age(X,A):-not(age(X,A)), write('what is your age?'), read(A), nl, asserta(age(X,A)).

moderate_risk(X):-ask_marital_status(X,Y), Y=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000,!.
moderate_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I=<35000,!.
stable_risk(X):-ask_marital_status(X,M), M=married, ask_income(X,I), I=<50000, ask_mortgage(X,Z), Z>50000,!.
stable_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A>50, !.
high_risk(X):-ask_marital_status(X,M), M=single, ask_income(X,I), I>35000, ask_age(X,A), A=<50, !.

invest(X,oil):-stable_risk(X),!.
invest(X,telecommunications):-moderate_risk(X),!.
invest(X,computers):-high_risk(X),!.

Третья «ask_martial_status» - это моя текущая попытка заставить пользователя повторно ввести свое решение, но оно не работает. Я пробовал это с оператором AND Пролога (,) и их или оператором (;) - не имеет значения (для того, что я помещаю между Y \ = замужем и Y \ = одиноким). Когда я ввожу ошибочный ввод, я просто получаю «ложь». Ниже приведен пример:

?- main(X,Z).
what is your name?logan.
what is your marital status: married or single?|: widowed.

false.

Закомментированная строка (с%) была предыдущей попыткой заставить программу работать, но она также не удалась. Я удивлен, что не смог найти краткое видео / статью на YouTube, чтобы прочитать, когда я решил эту проблему в Google. Может ли кто-нибудь помочь мне здесь?

Ответы [ 2 ]

1 голос
/ 07 марта 2020

Традиционный способ чтения и проверки ввода пользователя заключается в использовании следующего шаблона:

ask(Data) :-
    repeat,
        write(Prompt),
        read(Data),
    valid(Data),
    !.

Применяя этот шаблон к вашему случаю, мы можем написать:

ask_marital_status(Status) :-
    repeat,
        write('What is your marital status (married or single)?'),
        read(Status)
    (   Status == married
    ;   Status == single
    ),
    !.

Как Общее правило - это лучшая практика, чтобы отделить запрос пользователя от обработки ввода (утверждение факта в вашем случае).

Решения высокого уровня будут использовать механизмы печати сообщений и вопросов для взаимодействия с пользователем (см., например, https://logtalk.org/2019/11/14/abstracting-user-interaction.html). Но это более продвинутый топи c.

0 голосов
/ 07 марта 2020

Вы можете решить свою проблему следующим образом (фрагмент соответствующего префоката):

ask_marital_status(X,Y):-
    \+ marital_status(X,Y), 
    write('what is your marital status: married or single?'), 
    read(Y1),
    ( (Y1 == single ; Y1 == married) -> 
        Y = Y1,
        asserta(marital_status(X,Y)); 
        ask_marital_status(X,Y)
    ).

Вы можете проверить, является ли значение, которое вы прочитали (Y1), single или married с помощью (Y1 = single ; Y1 = married) (; означает или). Затем, если это так (->), вы переходите к остальной части предиката. В противном случае (после ; рядом с asserta/1) вы звоните recursively marital_status/2.

РЕДАКТИРОВАТЬ: благодаря комментарию Пауло Моуры, =/2 (объединение) должно быть заменено на ==/2 (равенство) , чтобы заставить код вести себя как положено.

...