clips

Function modify in CLIPS


I am solving a problem in which I need to build a tower from an unordered heap of blocks, and the size of the blocks should go from the largest to the smallest. I wrote the following code with the templates I need:

(deftemplate block 
  (slot size (type INTEGER))
  (slot place (type SYMBOL))
  (slot color (type SYMBOL))
)

(deftemplate on 
  (slot upper (type SYMBOL))
  (slot lower (type SYMBOL))
  (slot place (type SYMBOL)(default heap))
)

(deftemplate goal 
  (slot current-task (type SYMBOL))
)

(deffacts initial-state
  (block (size 5) (place heap) (color brown))
  (block (size 25) (place heap) (color white))
  (block (size 14) (place heap) (color blue))
  (block (size 12) (place heap) (color yellow))
)

As well as the rest of the program logic:

(defrule set-initial-task
  (initial-fact)
  =>
  (assert (goal (current-task find)))
)

(defrule find-largest-block
  (goal (current-task find))
  (block (size ?size) (place heap))
  (not (block (size ?larger-size&:(> ?larger-size ?size)) (place heap)))
  =>
  (modify (block (size ?size) (place hand)))
  (modify (goal (current-task build)))
)

(defrule place-first-block
  (goal (current-task build))
  (block (size ?size) (place hand))
  (not (block (place tower)))
  =>
  (modify (block (size ?size) (place tower)))
  (modify (goal (current-task find)))
  (printout t "Placed block " ?size " on the base of the tower." crlf)
)

(defrule place-next-block
  (goal (current-task build))
  (block (size ?size) (place hand) (color ?color1))
  (block (size ?lower-size) (place tower) (color ?color2))
  (not (on (upper ?lower-size)))
  =>
  (modify (block (size ?size) (place tower) (color ?color1)))
  (assert (on (upper ?lower-size) (lower ?size)))
  (modify (goal (current-task find)))
  (printout t "Placed block " ?size " on top of " ?lower-size "." crlf)
)

(defrule end-process
  (goal (current-task build))
  (not (block (place heap)))
  =>
  (retract (goal (current-task build)))
  (printout t "The tower has been built." crlf)
)

But when uploading a file to CLIPS I get errors in each modify function:

Defining defrule: find-largest-block [ARGACCES5] Function modify expected argument #1 to be of type non-void return value

Tell me what is wrong with my code.


Solution

    1. Don't use the initial-fact in your patterns. It's no longer supported, and when it was, it was automatically added to rules when needed.
    2. You're using an assert style syntax for the modify and retract function calls, but if you look at the documentation or almost any program using fact patterns, you'll see you need to bind the fact matching the pattern to a variable which can then be referenced by these functions in the actions of the rule.
    3. The upper and lower slots in deftemplate on need to be given a type of INTEGER rather than SYMBOL, otherwise you will get an error in your place-next-block rule when you try to assign these slots an integer value from the size slot of the block.
    4. The end-process rule needs to be applicable during the find task, not the build task. When the place-next-block rules executes for the last block, it will change the task to find and this will deactivate the end-process-rule.

    Once you correct these issues, your program runs correctly:

            CLIPS (6.4 2/9/21)
    CLIPS> 
    (deftemplate block 
      (slot size (type INTEGER))
      (slot place (type SYMBOL))
      (slot color (type SYMBOL))
    )
    CLIPS> 
    (deftemplate on 
      (slot upper (type INTEGER))
      (slot lower (type INTEGER))
      (slot place (type SYMBOL)(default heap))
    )
    CLIPS> 
    (deftemplate goal 
      (slot current-task (type SYMBOL))
    )
    CLIPS> 
    (deffacts initial-state
      (block (size 5) (place heap) (color brown))
      (block (size 25) (place heap) (color white))
      (block (size 14) (place heap) (color blue))
      (block (size 12) (place heap) (color yellow))
    )
    CLIPS> 
    (defrule set-initial-task
      =>
      (assert (goal (current-task find)))
    )
    CLIPS> 
    (defrule find-largest-block
      ?g <- (goal (current-task find))
      ?b <- (block (size ?size) (place heap))
      (not (block (size ?larger-size&:(> ?larger-size ?size)) (place heap)))
      =>
      (modify ?b (place hand))
      (modify ?g (current-task build))
    )
    CLIPS> 
    (defrule place-first-block
      ?g <- (goal (current-task build))
      ?b <- (block (size ?size) (place hand))
      (not (block (place tower)))
      =>
      (modify ?b (place tower))
      (modify ?g (current-task find))
      (printout t "Placed block " ?size " on the base of the tower." crlf)
    )
    CLIPS> 
    (defrule place-next-block
      ?g <- (goal (current-task build))
      ?b <- (block (size ?size) (place hand) (color ?color1))
      (block (size ?lower-size) (place tower) (color ?color2))
      (not (on (upper ?lower-size)))
      =>
      (modify ?b (place tower))
      (assert (on (upper ?lower-size) (lower ?size)))
      (modify ?g (current-task find))
      (printout t "Placed block " ?size " on top of " ?lower-size "." crlf)
    )
    CLIPS> 
    (defrule end-process
      ?g <- (goal (current-task find))
      (not (block (place heap)))
      =>
      (retract ?g)
      (printout t "The tower has been built." crlf)
    )
    CLIPS> (reset)
    CLIPS> (run)
    Placed block 25 on the base of the tower.
    Placed block 14 on top of 25.
    Placed block 12 on top of 14.
    Placed block 5 on top of 12.
    The tower has been built.
    CLIPS>