Search code examples
clips

How to model facts in an object-oriented way?


I love clips and am quite comfortable using it to define rules, I want to use it for an upcoming project. However, I need to execute some rules on XML files. I have a bunch of XMLs and I need to extract some outputs, insights from them. I wanted to ask for guidance here, is there any pattern to model objects as clips facts?


Consider this following example:

<families>
    <family>
        <children>
            <boy age="11"/>
            <girl age="12"/>
        </children>
        <parent>
            <father age="31"/>
            <mother age="29"/>
        </parent>
    </family>
</families>

How would I translate this to facts in clips, and write a rule that'll output the number of boys whose mother is older than the father?

Thank you,


Solution

  • It would be better to use objects rather than facts since you would be able to take advantage of inheritance, but you can implement this with facts by assigning a name for each fact and use this as a symbolic link to represent the nested structure of the XML:

             CLIPS (6.31 6/12/19)
    CLIPS>    
    (deftemplate family
       (slot name)
       (slot progenitor (default none))
       (multislot children)
       (multislot parent))
    CLIPS>       
    (deftemplate boy
       (slot name)
       (slot progenitor (default none))
       (slot age))
    CLIPS>    
    (deftemplate girl
       (slot name)
       (slot progenitor (default none))
       (slot age))
    CLIPS>    
    (deftemplate father
       (slot name)
       (slot progenitor (default none))
       (slot age))
    CLIPS> 
    (deftemplate mother
       (slot name)
       (slot progenitor (default none))
       (slot age))
    CLIPS>    
    (deffacts data
       (boy-count)
       (family (name family-1)
               (children boy-1 girl-1)
               (parent father-1 mother-1))
       (boy (name boy-1)
            (progenitor family-1)
            (age 11))
       (girl (name girl-1)
             (progenitor family-1) 
             (age 13)) 
       (father (name father-1)
               (progenitor family-1)
               (age 31))
       (mother (name mother-1)
               (progenitor family-1) 
               (age 29))      
       (family (name family-2)
               (children boy-2 boy-3)
               (parent father-2 mother-2))
       (boy (name boy-2)
            (progenitor family-2)
            (age 14))
       (boy (name boy-3)
            (progenitor family-2) 
            (age 16)) 
       (father (name father-2)
               (progenitor family-2)
               (age 35))
       (mother (name mother-2)
               (progenitor family-2) 
               (age 43)))
    CLIPS>              
    (defrule add-boy
       (family (name ?family))
       (father (age ?fa) (progenitor ?family))
       (mother (age ?ma&:(> ?ma ?fa)) (progenitor ?family))
       (boy (name ?boy) (progenitor ?family))
       ?bc <- (boy-count $?names&:(not (member$ ?boy ?names)))
       =>
       (retract ?bc)
       (assert (boy-count ?names ?boy)))
    CLIPS> 
    (defrule print-count
       (declare (salience -10))
       (boy-count $?names)
       =>
       (bind ?count (length$ ?names))
       (switch ?count
          (case 0 then (printout t "There are no boys"))
          (case 1 then (printout t "There is 1 boy"))
          (default then (printout t "There are " ?count " boys")))
       (printout t " with a mother older than a father." crlf))
    CLIPS> (reset)
    CLIPS> (run)
    There are 2 boys with a mother older than a father.
    CLIPS>