Dustin
Dustin

Reputation: 143

What is the syntax for reading a slot value of an object, where that object is a variable, and inside a defrule?

I've been digging through the documentation and couldn't find the solution, so forgive me if I missed this somewhere. Here's my problem: I have two instances of the PART class, part1 and part2, and the PART class has a slot named hasPort. I want a rule that matches on two part instances if the ports are connected. Each port is an instance of the PORT class that has a slot named 'connectedTo' that is used to store the connecting PORT instance.

First, my class objects:

(defclass PART  (is-a USER)
   (role concrete)
   (slot affectsProperty (type INSTANCE))
   (slot directlyConnected (type INSTANCE))
   (slot hasPort (type INSTANCE))
   (slot hasSensor (type INSTANCE))
   (slot hasIssue (type INSTANCE))
   (multislot secondary-types))

(defclass PORT  (is-a USER)
   (role concrete)
   (slot connectedTo (type INSTANCE))
   (multislot secondary-types))

I tried rules like the following:

(defrule rule0
   ?part1 <- (object (is-a PART) (hasPort ?port1))
   ?part2 <- (object (is-a PART) (hasPort ?port2))
   ?port1 <- (object (is-a PORT) (connectedTo ?port2))
   =>  
   ;(assert (directlyConnected ?part1 ?part2))
   (printout t "Found connected parts "
     (instance-name ?part1) " "
     (instance-name ?part2) " by ports "
     (instance-name ?port1) " "
     (instance-name ?port2)
     crlf))

I also tried something like the following:

(defrule rule0
   ?part1 <- (object (is-a PART) (hasPort ?port1))
   ?part2 <- (object (is-a PART) (hasPort ?port2))
   ?port2 <- (send ?port1 get-connectedTo)
   =>  
   ;(assert (directlyConnected ?part1 ?part2))
   (printout t "Found connected parts "
     (instance-name ?part1) " "
     (instance-name ?part2) " by ports "
     (instance-name ?port1) " "
     (instance-name ?port2)
     crlf))

and even something like the following:

(defrule rule0
   ?part1 <- (object (is-a PART) (hasPort ?port1))
   ?part2 <- (object (is-a PART) (hasPort ?port2))
   ?port3 <- (send ?port1 get-connectedTo)
   (test (eq ?port3 ?port2))
   =>  
   ;(assert (directlyConnected ?part1 ?part2))
   (printout t "Found connected parts "
     (instance-name ?part1) " "
     (instance-name ?part2) " by ports "
     (instance-name ?port1) " "
     (instance-name ?port2)
     crlf))

Besides what is possible, if you can share which approach is the most "clips"-natural way to write this rule, that would super appreciated.

Upvotes: 0

Views: 405

Answers (1)

Gary Riley
Gary Riley

Reputation: 10757

Your first rule will work if you place the third pattern first so that the variable ?port1 is bound to the instance address before being referenced by the hasPort slot.

         CLIPS (6.31 6/12/19)
CLIPS> 
(defclass PART  (is-a USER)
   (role concrete)
   (slot affectsProperty (type INSTANCE))
   (slot directlyConnected (type INSTANCE))
   (slot hasPort (type INSTANCE))
   (slot hasSensor (type INSTANCE))
   (slot hasIssue (type INSTANCE))
   (multislot secondary-types))
CLIPS> 
(defclass PORT  (is-a USER)
   (role concrete)
   (slot connectedTo (type INSTANCE))
   (multislot secondary-types))
CLIPS>    
(defrule rule0
   ?port1 <- (object (is-a PORT) (connectedTo ?port2))
   ?part1 <- (object (is-a PART) (hasPort ?port1))
   ?part2 <- (object (is-a PART) (hasPort ?port2))
   =>  
   (printout t "Found connected parts "
     (instance-name ?part1) " "
     (instance-name ?part2) " by ports "
     (instance-name ?port1) " "
     (instance-name ?port2)
     crlf))
CLIPS> (make-instance port2 of PORT)
[port2]
CLIPS> (make-instance port1 of PORT (connectedTo (instance-address [port2])))
[port1]
CLIPS> (make-instance part1 of PART (hasPort (instance-address [port1])))
[part1]
CLIPS> (make-instance part2 of PART (hasPort (instance-address [port2])))
[part2]
CLIPS> (run)
Found connected parts [part1] [part2] by ports [port1] [port2]
CLIPS>

Rather than using instance-addresses for the slot values, you can link the instances together using the instance names together with the predefined name slot for each instance.

CLIPS> (clear)
CLIPS> 
(defclass PART  (is-a USER)
   (role concrete)
   (slot affectsProperty (type INSTANCE-NAME))
   (slot directlyConnected (type INSTANCE-NAME))
   (slot hasPort (type INSTANCE-NAME))
   (slot hasSensor (type INSTANCE-NAME))
   (slot hasIssue (type INSTANCE-NAME))
   (multislot secondary-types))
CLIPS> 
(defclass PORT  (is-a USER)
   (role concrete)
   (slot connectedTo (type INSTANCE-NAME))
   (multislot secondary-types))
CLIPS>    
(defrule rule0
   (object (is-a PART) (name ?part1) (hasPort ?port1))
   (object (is-a PART) (name ?part2) (hasPort ?port2))
   (object (is-a PORT) (name ?port1) (connectedTo ?port2))
   =>  
   (printout t "Found connected parts " ?part1 " " ?part2 
               " by ports " ?port1 " " ?port2 crlf))
CLIPS> (make-instance port1 of PORT (connectedTo [port2]))
[port1]
CLIPS> (make-instance port2 of PORT)
[port2]
CLIPS> (make-instance part1 of PART (hasPort [port1]))
[part1]
CLIPS> (make-instance part2 of PART (hasPort [port2]))
[part2]
CLIPS> (run)
Found connected parts [part1] [part2] by ports [port1] [port2]
CLIPS> 

Upvotes: 1

Related Questions