Is there a function in CLIPS which checks if all/any/none of the elements in a multifields match a predicate?

24 Views Asked by At

I am aware of the member$ function in CLIPS. But its downside is that it only works on literal values as input. Does CLIPS have all/any/none functions where the elements are tested for a predicate? Something that would probably look like: (for-all <range-var> <source> <predicate>).

The problem I'm facing:

(deftemplate list (multislot vals))

(defrule first-high-val
    (list
        (vals
            $?b ;; all of these should be less than or equal to 10
            ?x  ;; first value to be greater than 10
            $?e
    )   )
    (test (for-all ?k $?b (<= ?k 10)))
=>
    (println ?x)
)

Simply doing:

(defrule first-high-val
    (list
        (vals
            $?b
            ?x & :(> ?x 10)
            $?e
    )   )
=>
    (println ?x)
)

is incorrect, because for (4 2 7 4 33 5 9 3 11 8 3 0) the rule would have an activation for 33 and for 11 respectively, while 11 is not the first number to be greater than 10.

1

There are 1 best solutions below

0
Gary Riley On BEST ANSWER

There's a foreach function which allows you to apply actions to every member of a list, but there's not a comparable function for seeing if every member satisfies a query. You can write a deffunction that will do the iteration and predicate test for you:

CLIPS> (deftemplate list (multislot vals))
CLIPS> 
(deffunction for-every (?list ?op ?value)
   (foreach ?item ?list
      (if (not (funcall ?op ?item ?value)) then (return FALSE)))
   (return TRUE))
CLIPS> 
(defrule first-high-val
   (list (vals $?b ?x&:(> ?x 10) $?e))
   (test (for-every ?b <= 10))
   =>
   (println ?x))
CLIPS> (assert (list (vals 4 2 7 4 33 5 9 3 11 8 3 0)))
<Fact-1>
CLIPS> (run)
33
CLIPS>