Menu

#14 defmodule defrule run does not initially println to stdout

CLIPS
open
nobody
None
5
2024-06-07
2024-06-06
No

I see some odd behavior using defmodules, specifically upon first run when I define a rule that prints to STDOUT. Please see the below sequence of CLIPS code:

         CLIPS (6.4.1 4/8/23)
CLIPS> (defmodule foo)
CLIPS> (defrule do-it (f ?f) => (println "FOO facts") (facts) (focus MAIN) (println "MAIN facts") (facts) (assert (f ?f)))
CLIPS> (assert (f 1))
<Fact-1>
CLIPS> (run)
CLIPS> (facts)
f-1     (f 1)
For a total of 1 fact.
CLIPS> (focus foo)
TRUE
CLIPS> (facts)
f-1     (f 1)
For a total of 1 fact.
CLIPS> (assert (f 2))
<Fact-2>
CLIPS> (get-current-module)
foo
CLIPS> (run)
FOO facts
f-1     (f 1)
f-2     (f 2)
For a total of 2 facts.
MAIN facts
FOO facts
f-1     (f 1)
f-2     (f 2)
For a total of 2 facts.
MAIN facts

Discussion

  • Gary Riley

    Gary Riley - 2024-06-07

    When you first issue a (run) command. the MAIN module is the only module on the focus stack. The activation for the do-it rule is on the agenda for the foo module, however, so issuing a (run) command doesn't fire any rules. The only effect the run has is to remove the MAIN module from the focus stack. The do-it rule still remains on the agenda for foo.

             CLIPS (6.4.1 4/8/23)
    CLIPS> (defmodule foo)
    CLIPS> (defrule do-it (f ?f) =>)
    CLIPS> (assert (f 1))
    <Fact-1>
    CLIPS> (agenda)
    0      do-it: f-1
    For a total of 1 activation.
    CLIPS> (agenda *)
    MAIN:
    foo:
       0      do-it: f-1
    For a total of 1 activation.
    CLIPS> (list-focus-stack)
    MAIN
    CLIPS> (watch rules)
    CLIPS> (run)
    CLIPS> (list-focus-stack)
    CLIPS> (agenda *)
    MAIN:
    foo:
       0      do-it: f-1
    For a total of 1 activation.
    CLIPS> 
    

    There are two concepts in play here: the current module and the focus stack. The current module is used to determine where new constructs are added and also as the default value for some commands which optionally take a module as an argument. When you define a defmodule, the current module is automatically set to the new module so that constructs that follow do not have to explicitly use a module specifier in the construct name.

    The focus command pushes one or more modules onto the focus stack. It does not change the current module. When a rule finishes executing, the focus stack is checked to see if there's an activation of a rule belonging to the module on the top of the stack. If so, the rule is executed and the current module is set to the module of the rule. If the top module contains no activations, then it's popped from the stack and focus switch to the next module.

    When your do-it rule is compiled, the pattern (f ?f) in the rule creates an implied deftemplate f belonging to the foo module. When the (assert (f ?f)) command in the action is parsed, the reference to the f deftemplate is resolved at that time. The current-module or focus has no effect on where that fact will be created (the foo module). If you wanted the do-it rule to assert the fact in the MAIN module, you need to change the current module using set-current-module and then use the str-assert function to create the fact because that will delay the creation of the implied f deftemplate until run-time.

    (set-current-module MAIN) (str-assert "(f 1)")

     
    👍
    1
    • Gary Riley

      Gary Riley - 2024-06-07

      One correction: focus does change the current module, but the other comments are still valid. The do-it rule is not executed in the initial run because foo is not on the focus stack and the fact assertion in the actions will attempt to assert in the foo module and not the MAIN module.

       
      👍
      1