Search code examples
clipsexpert-system

How to merge values of multiple lists into one list in CLIPS


I'm building a simple expert system for illness diagnosis. I have collected the symptoms of a patient and stored them in lists like so:

(patient_symptoms headache)
(patient_symptoms temperature)
(patient_symptoms cough)

I've also defined a template:

(deftemplate illness_matching
    (multislot symptom_names (type SYMBOL))
)

I'm trying to convert the values from "patient_symptoms" to a single instance of "illness_matching" template.

I have tried this:

(defrule convert_to_template
    (patient_symptoms $?all)
=>
    (assert (illness_matching (symptom_names ?all)))
)

The result:

(illness_matching (symptom_names headache))
(illness_matching (symptom_names temperature))
(illness_matching (symptom_names cough))

The result I'm expecting:

(illness_matching (symptom_names headache temperature cough))


Solution

  • Assuming your list of symptoms to be ordered facts which you assert one by one, you will need to persist the information of the current state of the illness in your rule so you can append the new symptoms.

    (defrule convert_to_template
      ; Merge a set of symptoms into a multifield
      ?illness_fact <- (illness_matching)
      ?symptom_fact <- (patient_symptom ?symptom)
      =>
      (modify ?illness_fact (symptom_names (insert$ (fact-slot-value ?illness_fact symptom_names) 1 ?symptom)))
      ; you want to retract the symptom to avoid a loop
      (retract ?symptom_fact))
    
    

    The modify statement allows you to change the value of an existing fact. Then you simply change the symptom_name slot with a new one which is the result of the old one (which you get via the fact-slot-value function) with the new symptom added at the beginning through the insert$ function.

    Example:

    Jupyter console 6.6.3
    
    iCLIPS
    In [1]: (deftemplate illness_matching
       ...:   (multislot symptom_names (type SYMBOL)))
    
    In [2]: (defrule convert_to_template
       ...:   ?illness_fact <- (illness_matching)
       ...:   ?symptom_fact <- (patient_symptom ?symptom)
       ...:   =>
       ...:   (modify ?illness_fact (symptom_names (insert$ (fact-slot-value ?illness_fact symptom_names) 1 ?symptom)))
       ...:   (retract ?symptom_fact))
    
    In [3]: (assert (illness_matching))
    (illness_matching (symptom_names))
    In [4]: (assert (patient_symptom fever))
    (patient_symptom fever)
    In [5]: (assert (patient_symptom nausea))
    (patient_symptom nausea)
    In [6]: (run)
    
    In [7]: (facts)
    f-1     (illness_matching (symptom_names fever nausea))
    For a total of 1 fact.