Search code examples
clipsexpert-system

CLIPS: Array in CLIPS? (Need some orientation, new in CLIPS)


I'm new in Clips. I'd like to know if it is a way to read an array (chain of numeric or characters with an index, sorry if it's the wrong name) on LHS. I have rules to ask for a value (s,cs,cn,n) then it assert the value to next asking rule, to finally read all the values in an answering rule to get a diagnostic, but in my small example I have 4 questions and 4 options for each one so mixing all the answers would give me 64 rules, and I have so at least 30 questions in my program so I think that would be too much rules (I'm doing my first Expert System an maybe this is normal). In any case I think I could get the values from questions into an array an read it in answering rules, but my questions are:

*How can I bind the values from my function into an array?
*Is it possible to verify that array in LHS?
*Do you have any other idea to verify the answer-rules? Hope you can help me.


    (deffunction funcionPregunta (?pregunta $?valoresAceptados) ;;ask-question function
            (printout t ?pregunta)
            (bind ?respuesta (read))
            (if (lexemep ?respuesta)
                    then (bind ?respuesta (lowcase ?respuesta)))
            (while (not (member$ ?respuesta ?valoresAceptados)) do 
                    (printout t ?pregunta)
            (bind ?respuesta (read))
            (if (lexemep ?respuesta)
                    then (bind ?respuesta (lowcase ?respuesta))))
            ?respuesta)

;;===============================================================
;;      QUESTION RULES
;;===============================================================


    (defrule pregunta1T5 "AGORAFOBIA"
            (not (diagnostico ?))
            =>
            (assert (Pregunta2T5
                    (funcionPregunta "1.Siente miedo o ansiedad marcada. (always/frecuently/rare/never)? "
                        s cs cn n))))
    
    (defrule Pregunta2T5 "AGORAPUBLICO"
            (not (diagnostico ?))
            (Pregunta2T5 ?Pregunta2T5)
            =>
            (assert (Pregunta3T5
            (funcionPregunta "2.Siente miedo en una multitud. (always/frecuently/rare/never)? "
                        s cs cn n)))
    )
    
    (defrule Pregunta3T5 "AGORAMIEDO"
            (not (diagnostico ?))
            (Pregunta3T5 ?Pregunta3T5)
            =>
            (assert (Pregunta4T5
            (funcionPregunta "3.Miedo de estar en una situacion. (always/frecuently/rare/never)? "
                        s cs cn n)))
    )
    
    (defrule Pregunta4T5 "AGORAANSIEDAD"
     ... ;; similar rules

;;===============================================================
;;      ANSWERS RULES
;;===============================================================


    (defrule Respuesta1T6 "RESULTADO 1 TAS"
            (not (diagnostico ?))
            (Pregunta2T6 s)(Pregunta3T6 s)(Pregunta4T6 s)(Pregunta5T6 s)
            =>
            (assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL"))
    )

(defrule Respuesta2T6 "RESULTADO 2 TAS"
        (not (diagnostico ?))
        (Pregunta2T6 cs)(Pregunta3T6 s)(Pregunta4T6 s)(Pregunta5T6 s)
        =>
        (assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL"))
)

Solution

  • In the case of the two answer rules you've already got, the simplest way to reduce the number of rules is just to combine them:

    (defrule Respuesta1T6-2T6
       (not (diagnostico ?))
       (Pregunta2T6 s | cs) ; s or cs is allowed
       (Pregunta3T6 s)
       (Pregunta4T6 s)
       (Pregunta5T6 s)
       =>
       (assert (diagnostico "TRASTORNO DE ANSIEDAD SOCIAL")))
    

    If you're creating lots of rules that differ only in the constants matched in the patterns, you should consider representing the rules as a combination of facts containing these constants and generic rules to process that data. For example, you could rewrite your question rules like this:

    (deftemplate Pregunta      ; question
       (slot identidad)        ; ID
       (slot texto)            ; text
       (multislot respuestas)  ; responses
       (slot precursora        ; precursor
          (default ninguna)))  ; none
    
    (deftemplate Responder     ; answer
       (slot identidad)        ; ID
       (slot valor))           ; value
           
    (deffacts Preguntas
       (Pregunta (identidad AGORAFOBIA)
                 (texto "1. Siente miedo o ansiedad marcada. (always/frecuently/rare/never)? ")
                 (respuestas s cs cn n))
       (Pregunta (identidad AGORAPUBLICO)
                 (texto "2. Siente miedo en una multitud. (always/frecuently/rare/never)? ")
                 (respuestas s cs cn n)
                 (precursora AGORAFOBIA))
       (Pregunta (identidad AGORAMIEDO)
                 (texto "3. Miedo de estar en una situacion. (always/frecuently/rare/never)? ")
                 (respuestas s cs cn n)
                 (precursora AGORAPUBLICO)))
    
    (defrule pedir-pregunta ; ask question
       (not (diagnostico ?))
       (Pregunta (identidad ?id)
                 (texto ?t)
                 (respuestas $?r)
                 (precursora ?p))
       (or (test (eq ?p ninguna))
           (Responder (identidad ?p)))
       =>
       (assert (Responder (identidad ?id)
                          (valor (funcionPregunta ?t ?r)))))
    

    And your diagnosis rules like this:

    (deftemplate Trastorno   ; disorder
       (slot nombre)         ; name
       (multislot sintomas)) ; symptoms
       
    (deftemplate Sintoma
       (slot identidad)      ; ID
       (slot responder)      ; answer
       (multislot valors))   ; values
    
    (deffacts Trastornos
       (Trastorno (nombre "TRASTORNO DE ANSIEDAD SOCIAL")
                  (sintomas AGORAFOBIA-cs-s AGORAPUBLICO-s AGORAMIEDO-s)))
                  
    (deffacts Sintomas
       (Sintoma (identidad AGORAFOBIA-cs-s)
                (responder AGORAFOBIA)
                (valors cs s))
       (Sintoma (identidad AGORAPUBLICO-s)
                (responder AGORAPUBLICO)
                (valors s))
       (Sintoma (identidad AGORAMIEDO-s)
                (responder AGORAMIEDO)
                (valors s)))
       
    (defrule Respuesta
       (not (diagnostico ?))
       (Trastorno (nombre ?n))                 ; There is a disorder.
       (forall (Trastorno (nombre ?n)          ; For every symptom
                          (sintomas $? ?s $?)) ; of the disorder,
               (Sintoma (identidad ?s)         ; there is a list
                        (responder ?r)         ; of possible values
                        (valors $?sv))         ; for that symptom
               (Responder (identidad ?r)       ; matched by a response.
                          (valor ?v&:(member$ ?v ?sv))))
       =>
       (assert (diagnostico ?n)))