Как сравнить список с базой данных Пролог - PullRequest
0 голосов
/ 15 февраля 2019

У меня есть база данных фактов, в которой есть записи, подобные этому фрагменту

symptom(shingles,headache).    
symptom(shingles,fever).    
symptom(shingles,malaise).    
symptom(shingles,headache).    
symptom(shingles,itching).    
symptom(shingles,hyperesthesia).    
symptom(shingles,paresthesia).   

test(shingles,blood).    
test(shingles,pcr).   

locale(shingles,all).  

treatment(shingles,calamine).    
treatment(shingles,aciclovir).

treatment(shingles,valaciclovir).    
treatment(shingles,famciclovir).    
treatment(shingles,corticosteroids).

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

getSymptoms(Symptoms) :-
    write('Please enter symptoms now, enter "Done" when finished: ' ),
    read_string(user, "\n", "\r", _, Response),
    (
        Response == "Done"
    ->
        Symptoms = []
    ;
        getSymptoms(Symptoms0),
        Symptoms = [Response|Symptoms0]
    ).

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

1 Ответ

0 голосов
/ 16 февраля 2019

Это будет работать, но позволяет вводить повторяющиеся симптомы.Я публикую его сейчас, чтобы вы могли увидеть первую часть преобразования и опубликую часть без дубликатов, когда я получу эту работу.

getSymptoms(Symptoms) :-
    write('Please enter symptoms now, enter "Done" when finished: ' ),
    read_string(user, "\n", "\r", _, Response),
    (
        Response == "Done"
    ->
        Symptoms = []
    ;
        atom_string(Symptom,Response),
        valid_symptom(Symptom,Symptoms)
    ).

valid_symptom(Symptom,Symptoms) :-
    (
        symptom(_,Symptom)
    ->
        % Symptom was valid
        % so get next symptom and
        % add to list on backtracking
        getSymptoms(Symptoms0),
        Symptoms = [Symptom|Symptoms0]
    ;
        % Symptom was invalid
        % so warn user of invalid symptom and what they input
        % and get next symptom.
        % Do not add invalid Symptom to list on backtracking.
        format('Invalid symptom: `~w''~n',[Symptom]),
        getSymptoms(Symptoms0),
        Symptoms = Symptoms0
    ).

Поскольку введенные значения являются строками, а симптомы - атомами в symptom/2 фактах, входные данные необходимо преобразовать в атом для сравнения.Это делается с помощью atom_string / 2

atom_string(Symptom,Response) 

Чтобы дать пользователю обратную связь, если признак недействителен, используется format / 2 .Лучше использовать, чем write / 1 , поскольку это дает вам больший контроль над выводом.

format('Invalid symptom: `~w''~n',[Symptom])

Если для симптома введено недопустимое значение, его не следует добавлять ксписок.Это классический сценарий типа if / then, а в Prolog это делается с помощью -> / 2 .Вот стандартный шаблон

(
    <conditional>
->
    <true branch>
;
    <false branch>
)

, условное выражение

symptom(_,Symptom)

Обратите внимание также на условное условие, что он считывает факты symptom/2 и игнорирует первую часть составной структуры,то есть _, и сопоставляет входной симптом с симптомом в фактах.Это сравнение выполняется, но выполняется с помощью объединения, а не предиката сравнения, например == / 2 .

Истинная ветвь такая же, как и раньше

getSymptoms(Symptoms0),
Symptoms = [Symptom|Symptoms0]

однако ложная ветвь равна

format('Invalid symptom: `~w''~n',[Symptom]),
getSymptoms(Symptoms0),
Symptoms = Symptoms0

Обратите внимание, что неверный Symptom не добавлен в список с [Symptom|Symptoms0], а также что обе ветви (истина и ложь) должны обновитьте же переменные, Symptoms, которые в ложной ветви выполняются с Symptoms = Symptoms0, который не является присваиванием, но = / 2 (объединение).

Код для valid_symptom/2 может иметьбыло добавлено getSymptoms/1, но я вытащил его, чтобы вы могли видеть, как это делается на случай, если вам понадобится сделать это в будущем.

Пример выполнения:

?- getSymptoms(Symptoms).
Please enter symptoms now, enter "Done" when finished: wrong
Invalid symptom: `wrong'
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: malaise
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: Done
Symptoms = [headache, malaise, headache].

Вот следующий вариант, который удаляет дубликаты при построении списка.

getSymptoms(Result) :-
    getSymptoms_helper([],Result).

getSymptoms_helper(Symptoms,Result) :-
    write('Please enter symptoms now, enter "Done" when finished: ' ),
    read_string(user, "\n", "\r", _, Response),
    (
        Response == "Done"
    ->
        Result = Symptoms
    ;
        atom_string(Symptom,Response),
        valid_symptom(Symptom,Symptoms,Result)
    ).

valid_symptom(Symptom,Symptoms,Result) :-
    (
        memberchk(Symptom,Symptoms)
    ->
        % Symptom was a duplicate
        % Do not add duplicate Symptom to list.
        getSymptoms_helper(Symptoms,Result)
    ;
        (
            symptom(_,Symptom)
        ->
            % Symptom was valid
            % so get next symptom and
            % add to list.
            getSymptoms_helper([Symptom|Symptoms],Result)
        ;
            % Symptom was invalid
            % so warn user of invalid symptom and what they input
            % and get next symptom.
            % Do not add invalid Symptom to list.
            format('Invalid symptom: `~w''~n',[Symptom]),
            getSymptoms_helper(Symptoms,Result)
        )
    ).

Основное изменение здесь состоит в том, что аккумулятор Symptoms пронизывает предикаты, чтобы можно было составить список допустимых симптомов ииспользуется для проверки следующего входного значения.Так как аккумулятор должен быть инициализирован при запуске, предыдущий предикат был переименован в getSymptoms_helper, чтобы аккумулятор мог инициализироваться с помощью

getSymptoms_helper([],Result)

Уведомления [], который передается в

getSymptoms_helper(Symptoms,Result)

, таким образом, устанавливая начальное значение Symptoms в [].

Когда введено Done, список объединяется с Result и передается обратно при обратной цепочке.Обычно переменные называются Symptoms0 и Symptoms, но я сохранил их таким образом, чтобы им было легче следить.В противном случае могут быть переменные Symptom, Symptoms и Symptoms0, но после того, как вы к ним привыкнете, вам будет легче следить.

Проверка на наличие дубликатов выполняется с помощью memberchk / 2 , что лучше, чем использовать member / 2 для проверки.Опять же, это добавляет еще одно условие к миксу.

Пример выполнения:

?- getSymptoms(Symptoms).
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: malaise
Please enter symptoms now, enter "Done" when finished: headache
Please enter symptoms now, enter "Done" when finished: Done
Symptoms = [malaise, headache].
...