-2

what I am trying to accomplish is using a database of disease facts

symptom(shingles,headache).
symptom(shingles,fever).
symptom(shingles,malaise).
symptom(shingles,headache).
symptom(smallpox,fever).
symptom(smallpox,rash).

and compare it with a list of symptoms from the user. I can currently get the symptoms from the user and add the disease to a list, however, I cant figure out how to loop through the entier database to add all the possible diseases it could be.

start:-
    consult(diseases1),
    getSymptoms(Symptoms),
    write(Symptoms).

welcome:-
        write('Welcome to the Disease Diagnostic Center'),nl,nl.

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)
->
    getSymptoms(Symptoms0),
    foreach(symptom(Y,Symptom),write(Y))
;
    format('Invalid symptom: `~w''~n',[Symptom]),
    getSymptoms(Symptoms0),
    Symptoms = Symptoms0
).  

So for example, the user enters fever as one of the symptoms, then the list should have in it shingles and smallpox. Currently I am able to write each possible disease to the screen, but I am not sure what to replace write with to be able to add each to a list.

lurker
  • 56,987
  • 9
  • 69
  • 103

1 Answers1

0

If you have a list with all you diseases, you can filter it by requiring a specific symptom.

All diseases:

all_diseases(Diseases) :-
    setof(Disease, Symptom^symptom(Disease, Symptom), Diseases).

?- all_diseases(D).
D = [shingles, smallpox].

Then filter it:

require_symptom(Symptom, Diseases0, Diseases) :-
    setof(Disease,
          ( member(Disease, Diseases0),
            symptom(Disease, Symptom)),
          Diseases)
    *-> true
    ; Diseases = [].

?- all_diseases(Ds), require_symptom(headache, Ds, D1).
Ds = [shingles, smallpox],
D1 = [shingles].

?- all_diseases(Ds), require_symptom(fever, Ds, D1).
Ds = D1, D1 = [shingles, smallpox].

?- all_diseases(Ds), require_symptom(vomiting, Ds, D1).
Ds = [shingles, smallpox],
D1 = [].

Output the list before and after filtering it.

firefrorefiddle
  • 3,795
  • 20
  • 31
  • Is there a particular reason you are using `(*->)/2` (a.k.a. "soft cut") in combination with `setof/3`? – repeat Mar 08 '19 at 12:53
  • 1
    @repeat I was actually surprised that `setof/3` didn't return the empty list if nothing was to be found, so I googled this question: https://stackoverflow.com/questions/20407430/prolog-how-to-do-setof-that-returns-empty-list-instead-of-failing with the proposed solution of (*->)/2. I thought it more reasonable to return the empty list here then just to fail. – firefrorefiddle Mar 08 '19 at 14:21
  • I see. I guess I'm just very wary about using `setof/3` nondeterministically and I would check for sufficient instantiation upfront (using `iwhen/2`)... – repeat Mar 08 '19 at 21:55