Building Rules Containing Python Functions

Help
Cerin
2010-07-14
2013-04-25
  • Cerin
    Cerin
    2010-07-14

    I'm trying to build rules in Clips that dynamically retrieves data from the Python interpreter. To do this, I register an external function as outlined in http://pyclips.sourceforge.net/manual/pyclips-overview.html#SECTION003250000000000000000

    However, when I try to create the rule, I get an error. What am I doing wrong?

    import clips
    def py_getvar(k):
        return globals().get(k)
    clips.RegisterPythonFunction(py_getglobal)
    # If globals().get('user') is not None: assert something
    clips.BuildRule("user-rule", "(neq (python-call py_getvar user) 'None')", "(assert (user-present))", "the user rule")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/lib/python2.6/dist-packages/clips/_clips_wrap.py", line 2839, in BuildRule
        _c.build(construct)
    _clips.ClipsError: C08: syntax error, or unable to parse expression
    
     
  • Hi,

    the part

    (neq (python-call py_getvar user) 'None')
    

    is not a valid LHS: on the LHS you can either have function calls (such as

    (test (neq (python-call py_getvar user) 'None'))
    

    and similar) or facts. However the above line is also not what you want: The Python value None, which is returned by globals().get(), is implicitly translated to the CLIPS SYMBOL nil, which has in CLIPS the same meaning as None in Python. The resulting LHS is thus

    (test (neq (python-call py_getvar user) nil))
    

    Please note that nil is not quoted. My advice is to manually specify conversions between the two systems every time: you can't assume that every value is converted to a string from one system to another, and _SYMBOL_s (which are used a lot in CLIPS) can be somewhat unusual for Python programmers.

    Cheers,

    F.

     
  • Ah, obviously the code you entered is not correct: it only works if you

    clips.RegisterPythonFunction(py_getvar)
    

    instead of py_getglobal! :-)

    F.

     
  • Cerin
    Cerin
    2010-07-28

    Thanks for the clarification. Sorry for the late reply. My monitoring settings weren't set correctly, and I was not notified of your reply.

    Making your modifications, I no longer get a syntax error. However, I still don't seem to be getting the desired output.

    My code is now:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    #!/usr/bin/python
    import os, sys
    import clips
    user = True
    def py_getvar(k):
        print globals().get(k)
        return (clips.Symbol('TRUE') if globals().get(k) else clips.Symbol('FALSE'))
    clips.RegisterPythonFunction(py_getvar)
    print clips.Eval('(python-call py_getvar user)')
    # if globals().get('user') is not None: assert something
    clips.BuildRule("user-rule", "(test (eq (python-call py_getvar user) TRUE))",
                    '(printout "user present!") (assert (user-present))',
                    "the user rule")
    clips.Run()
    print "Facts:"
    clips.PrintFacts()
    

    I would expect this to print "user present!" and show the fact (user-present), but this is not the case, implying the rule is not being trigger even though the LHS seems to be true. Why is this happening?

     
  • Cerin
    Cerin
    2010-07-28

    I think I've figured out the first part of my question. For some strange reason, it seems I needed to add clips.Reset() to trigger my rule.

    Is it possible to call Python functions in the RHS of a rule? I tried creating such a rule, and though it doesn't throw an error, it appears to completely block all rule execution. What would be causing that?

    import clips
    clips.Reset()
    user = True
    def py_getvar(k):
        return (clips.Symbol('TRUE') if globals().get(k) else clips.Symbol('FALSE'))
    clips.RegisterPythonFunction(py_getvar)
    def py_dostuff(k):
        print "doing stuff"
    clips.RegisterPythonFunction(py_dostuff)
    # if globals().get('user') is not None: assert something
    clips.BuildRule("user-rule", "(test (eq (python-call py_getvar user) TRUE))",
                    '(assert (user-present))',
                    "the user rule")
    clips.BuildRule("do-stuff-rule", "(we-should-do-stuff)",
                    '(python-call py_dostuff)',
                    "the do stuff rule")
    #clips.Assert('(we-should-do-stuff)') # breaks everything?
    clips.PrintAgenda()
    clips.Run()
    clips.PrintFacts()
    
     
  • Hi,

    the point is that, in CLIPS, you have to (reset) the environment to let it be able to work properly. Actually the "order" of doing things is:

    * define constructs (defrules, rules, deffacts, globals, …)
    * reset the environment
    * add facts
    * run against the constructs and facts
    * reset the environment
    * add facts
    * run against the constructs and facts
    * …

    The (reset) part is to let all the functions (including the (test) function) work properly. For instance, some functions (and not only (test) actually) need the (initial-fact) to be present, which is defined via the (reset) command.

    F.

     
  • Cerin
    Cerin
    2010-07-28

    Ah, thanks. That clears things up. It's all working fine now. The problem with functions in the RHS was due to my function having an extra argument that wasn't being passed.