Я хочу суммировать в SWI-Prolog в зависимости от ответов определенного пользователя - PullRequest
0 голосов
/ 14 мая 2019

Мне нужно суммировать в переменной в зависимости от ответов определенного пользователя, и я начинаю знать синтаксис и парадигму Пролога.

Прямо сейчас я могу читать пользовательские данные и распечатывать их, но у меня нет способа накапливать результаты, потому что сейчас результаты противоречивы.

Что у меня сейчас есть:

inicio :-
    write('¿You have overweight yes/no?'),
    read(R1),
    write('¿Are you a smoker yes/no?'),
    read(R2),
    write('¿Do you have some direct relative with diabetes?'),
    read(R3),
    Risk is 0,
    ( R1 = yes -> Risk is Risk + 2 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]),
    ( R2 = yes -> Risk is Risk + 1 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]),
    ( R3 = yes -> Risk is Risk + 3 ; Risk is Risk + 0 ),
    imprimir(['The result is ', Risk]).

imprimir([]).
imprimir([Term| Terms]) :-
    write(Term),
    imprimir(Terms).

1 Ответ

1 голос
/ 15 мая 2019

Я собираюсь показать вам принципиально иной подход к этой программе, который использует Пролог немного лучше.Во-первых, давайте составим таблицу штрафов.Создание таблиц для конфигурации вашей программы часто полезно:

risk_penalty(overweight, 2).
risk_penalty(smoker,     1).
risk_penalty(diabetes,   3).

Теперь, когда у нас есть единое представление о проблеме, давайте посмотрим, сможем ли мы сделать единый способ получения информации изпользователь.Давайте используем динамическое хранилище для отслеживания того, что сказал нам пользователь, потому что это упростит запросы позже:

:- dynamic risk/2.

ask(Prompt, Fact) :-
    format('~a [yes/no]> ', [Prompt]),
    read(Response),
    assertz(risk(Fact, Response)).

Теперь у нас есть небольшой предикат, который мы можем использовать для опроса пользователя.Такая функция print-read-assert довольно распространена в небольших экспертных системах, подобных вашей, потому что она помогает вам отделить логику системы от ее внешнего интерфейса.Когда вы делаете ask('Do you have X?', has_x), динамическое хранилище получает либо risk(has_x, yes), либо risk(has_x, no) в зависимости от того, какой пользователь вошел.Это также дает вам естественное место, чтобы сделать пользовательский ввод более надежным, проверив его и повторно спросив, получаете ли вы что-то странное.

Теперь мы можем сделать ваш начальный цикл немного более чётким:

inicio :-
    ask('Are you overweight?', overweight),
    ask('Are you a smoker?', smoker),
    ask('Do you have some direct relative with diabetes?', diabetes).

Это только часть интервью.Теперь, если вы пройдете через него один раз, ответив «да», «нет», «да», тогда база данных будет содержать следующие факты:

?- risk(Factor, Response).
Factor = overweight,
Response = yes ;
Factor = smoker,
Response = no ;
Factor = diabetes,
Response = yes.

Что нам нужно сделать сейчас, это выбрать «да»факторы, а затем посмотреть их штрафы и сложить их.Для этого мы можем использовать findall/3, который берет шаблон, цель и возвращает список результатов:

?- findall(risk(Factor, Response), risk(Factor, Response), Responses).
Responses = [risk(overweight, yes), risk(smoker, no), risk(diabetes, yes)].

Как вы видите, я использовал здесь тот же шаблон и цель, просточтобы увидеть все результаты, но мы можем поставить «да», чтобы отфильтровать его до факторов риска, о которых мы заботимся:

?- findall(risk(Factor), risk(Factor, yes), Responses).
Responses = [risk(overweight), risk(diabetes)].

Теперь вы можете видеть, что Шаблон (первый аргумент) - это всего лишьпроизвольная структура, заполненная переменными, которые findall/3 нашли, запустив Goal, второй аргумент.Таким образом, мы могли бы также просто получить список штрафных значений, если мы посмотрим их в запросе цели.Например:

?- findall(Penalty,    %% <- template
           (risk(Factor, yes), risk_penalty(Factor, Penalty)),   %% <- goal
           Penalties). %% <- result
Penalties = [2, 3].

Затем мы можем добавить всего 1030 *, чтобы сложить все:

?- findall(Penalty, 
           (risk(Factor, yes), risk_penalty(Factor, Penalty)), 
           Penalties), 
   sumlist(Responsa, Score).
Responsa = [2, 3],
Score = 5.

Теперь мы можем завершить предикат inicio/0:

inicio :-
    retractall(risk(_, _)),
    ask('Are you overweight?', overweight),
    ask('Are you a smoker?', smoker),
    ask('Do you have some direct relative with diabetes?', diabetes)
    findall(Penalty,
            (risk(Factor, yes), risk_penalty(Factor, Penalty)), Penalties),
    sumlist(Penalties, Score),
    format('The result is ~a~n', [Score]).

Теперь это выглядит так при запуске:

?- inicio.
Are you overweight? [yes/no]> yes.
Are you a smoker? [yes/no]> |: no.
Do you have some direct relative with diabetes? [yes/no]> |: yes.
The result is 5
true.

Надеюсь, вы найдете результат, на который приятно смотреть, гораздо менее процедурный, и его легче модифицировать и поддерживать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...