0
votes

I want to modify the code on Creating a list from user input with swi-prolog :

diagnose(Disease):-
    retractall(symptom(_)),
    getSymptoms(List),
    forall(member(X,List),assertz(symptom(X))),
    disease(Disease).

getSymptoms([Symptom|List]):-
    writeln('Enter Symptom:'),
    read(Symptom),
    dif(Symptom,stop),
    getSymptoms(List).
getSymptoms([]).

disease(flu):-
    symptom(fever),
    symptom(chills),
    symptom(nausea).
disease(cold):-
   symptom(cough),
   symptom(runny_nose),
   symptom(sore_throat).
disease(hungover):-
   symptom(head_ache),
   symptom(nausea),
   symptom(fatigue).

If I enter 3 symptoms: cough, nausea, fatigue, I should get output of number of symptoms present for different diseases, e.g.:

flu:  1
cold: 1
hungover: 2

How can I get this in Prolog? I know SWI-Prolog has an intersection function that can be used, but how exactly to apply it here?

?- intersection([fever, chills, nausea] ,[cough, nausea, fatigue], X).
X = [nausea].
1
I don't think the way the data is represented in the linked answer is the best approach. The way the "facts" for relating symptoms to illness are rendered doesn't provide flexibility in analyzing the information. I would have individual facts such as symptom(fever, flu). and symptom(chills, flu). etc. If you want to collect all of the symptoms for a given illness, you could use, findall(S, symptom(S, Illness), Symptoms) and use the list of Symptoms as needed.lurker
Looks much better. Why don't you enter this as answer.rnso
I shall do that. When I started the comment, I wasn't sure how far I was going to take it.lurker
I agree that is the best way to deal with this problem. But OP could use clause/2 to get the symptoms of the diseases as tuples, though, so that refactor is not entirely necessary. I feel like adding an answer that uses it could help OP and other people in the long runvmg
@vmg yes, that is true. clause/2 could be used here but I still do not think it is the best approach.lurker

1 Answers

1
votes

I don't think the way the data is represented in the linked answer is the best approach to representing such data. It's best to render the data as individual facts which is much more versatile. Thus, for example, the following is inflexible and obscures the individual symptom relationships:

disease(flu):-
    symptom(fever),
    symptom(chills),
    symptom(nausea).

The individual symptoms could be extracted using clause/2, as clause(disease(flu), Symptoms) would yield, Symptoms = (symptom(fever), symptom(chills), symptom(nausea)) and then the individual symptoms can be extracted from there.

I think it's clearer, however, to represent it as:

illness_symptom(flu, chills).
illness_symptom(flu, nausea).
illness_symptom(flu, fever).

If you want to collect the symptoms of a given illness into a list, you just use findall/3:

illness_symptoms(Illness, Symptoms) :-
    findall(Symptom, illness_symptom(Illness, Symptom), Symptoms).

Calling illness_symptoms(flu, Symptoms) would yield, Symptoms = [chills, nausea, fever].