Vintux
Vintux

Reputation: 43

Can we bind multislot values dynamically?

I am trying to get values out of multislots and dynamically assign it to variables.

Suppose we have a template as follows:

(fact (slot name)
      (multislot field)
      (multislot value))

(fact2 (slot field)
       (slot value))

Then can have a rule such as:

(rule
       (fact (name ?name)
             (field $?field)
             (value $?value))
       ;if length of field and value is greater than 0 
       (fact2 (field ?field1)
              (value ?value1))
       ;if length of field and value is greater than 1 
       (fact2 (field ?field2)
              (value ?value2))
       ;if length of field and value is greater than 2 
       (fact2 (field ?field3)
              (value ?value3))
       ;if length of field and value is greater than 3 
       (fact2 (field ?field4)
              (value ?value4))
=>
       (assert (all field:values found))

Here the fact can have just one field value pair or at max 4. I want a generic single rule which can be used to extract all the available values from multislot dynamically.

I guess in the above rule, we need not only to extract values but also implement a if length > 0, else-if kinda statements.

So if Input is:

(fact (name Employee)
      (field Name Role Department Company)
      (value Bob Admin Security ABC))
(fact2 (field Name)
       (value Bob))
(fact2 (field Role)
       (value Admin))
(fact2 (field Department)
       (value Security))
(fact2 (field Company)
       (value ABC))

Then expected output will be:

(all field:value pairs found)

while

(fact (name Employee)
      (field Name Role)
      (value Bob Admin))
(fact2 (field Name)
       (value Bob))
(fact2 (field Role)
       (value Admin))

While the same rule should also match the above facts. Is this possible? Or is there any alternative solution to the problem?

Thank you in advance.

Upvotes: 0

Views: 121

Answers (1)

Gary Riley
Gary Riley

Reputation: 10757

You can essentially iterate over each field/value using the forall conditional element. If the name slot dose not contain a unique value and you have multiple fact facts, you'll need to add a slot containing a unique value if you want to reason about the fact in the actions of the rule so that the fact pattern outside and inside the forall conditional element match the same fact.

         CLIPS (6.31 4/1/19)
CLIPS> 
(deftemplate fact
    (slot name)
    (slot id (default-dynamic (gensym*)))
    (multislot field)
    (multislot value))
CLIPS> 
(deftemplate fact2
    (slot field)
    (slot value))
CLIPS> 
(deffacts initial
   (fact (name Employee)
         (field Name Role Department Company)
         (value Bob Admin Security ABC))
   (fact (name Employee)
         (field Name Age)
         (value Bob 38))
   (fact2 (field Name)
          (value Bob))
   (fact2 (field Role)
          (value Admin))
   (fact2 (field Department)
          (value Security))
   (fact2 (field Company)
          (value ABC)))       
CLIPS>               
(defrule reasoning
   (fact (id ?id))
   (forall
      (fact (id ?id) 
            (field $?f ?field $?) 
            (value $?v&:(= (length$ ?f) (length$ ?v)) ?value $?))
      (fact2 (field ?field)
             (value ?value)))
   =>
   (assert (all field:values found)))
CLIPS> (reset)
CLIPS> (agenda)
0      reasoning: f-1,*
For a total of 1 activation.
CLIPS> (ppfact 1)
(fact 
   (name Employee) 
   (id gen1) 
   (field Name Role Department Company) 
   (value Bob Admin Security ABC))
CLIPS> 

Upvotes: 2

Related Questions