Question

Using PyClips, I'm trying to build rules in Clips that dynamically retrieve data from the Python interpreter. To do this, I register an external function as outlined in the manual.

The code below is a toy example of the problem. I'm doing this because I have an application with a large corpus of data, in the form of a SQL database, which I want to reason with using Clips. However, I don't want to waste time converting all this data into Clips assertions, if I can simply "plug" Clips directly into Python's namespace.

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

import clips

#user = True

#def py_getvar(k):
#    return globals().get(k)
def py_getvar(k):
    return True if globals.get(k) else clips.Symbol('FALSE')

clips.RegisterPythonFunction(py_getvar)

print clips.Eval("(python-call py_getvar user)") # Outputs "nil"

# If globals().get('user') is not None: assert something
clips.BuildRule("user-rule", "(neq (python-call py_getvar user) nil)", "(assert (user-present))", "the user rule")
#clips.BuildRule("user-rule", "(python-call py_getvar user)", "(assert (user-present))", "the user rule")

clips.Run()
clips.PrintFacts()
Was it helpful?

Solution

I received some help on the PyClips support group. The solution is to ensure your Python function returns a clips.Symbol object and use (test ...) to evaluate functions in the LHS of rules. The use of Reset() also appears to be necessary to activate certain rules.

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)

# 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.Run()
clips.PrintFacts()

OTHER TIPS

Your problem has something to do with the (neq (python-call py_getvar user) 'None'). Apparently clips doesn't like the nested statement. It appears that trying to wrap a function call in an equality statement does bad things. However you'll never assert the value anyway as your function returns either Nil or the value. Instead what you'll want to do is this:

def py_getvar(k):
    return clips.Symbol('TRUE') if globals.get(k) else clips.Symbol('FALSE')

then just change "(neq (python-call py_getvar user) 'None')" to "(python-call py_getvar user)"

And that should work. Haven't used pyclips before messing with it just now, but that should do what you want.

HTH!

>>> import clips
>>> def py_getvar(k):
...     return clips.Symbol('TRUE') if globals.get(k) else clips.Symbol('FALSE')

...
>>> clips.RegisterPythonFunction(py_getvar)
>>> clips.BuildRule("user-rule", "(python-call py_getvar user)", "(assert (user-
present))", "the user rule")
<Rule 'user-rule': defrule object at 0x00A691D0>
>>> clips.Run()
0
>>> clips.PrintFacts()
>>>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top