buguroo / pyknow

PyKnow: Expert Systems for Python
GNU Lesser General Public License v3.0
470 stars 141 forks source link

Matching list content using `CONTAINS` #33

Closed Behery closed 6 years ago

Behery commented 6 years ago

Is there a way for a rule to match against the content of a list (contains or in). In the following example, if parameters is a list and I want to match a bottle that's mentioned in that list, how do i do it?

@freeze.register(list)
def freeze_list(l):
    return ";".join(l)

class Bottle(Fact):
    name = Field(str, default=None)

class Action(Fact):
    name = Field(str, default=None)
    parameters = Field(list, default=[])

@Rule(AND(Bottle(name=MATCH.name),
              Action(parameters=MATCH.params & CONTAINS(MATCH.name))))

I'm getting the following error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/mbehery/workspace/science/behery2019graph/scripts/world_parser.py", line 95, in <module>
    class Kitchen(KnowledgeEngine):
  File "/home/mbehery/workspace/science/behery2019graph/scripts/world_parser.py", line 158, in Kitchen
    Action(parameters=MATCH.params & CONTAINS(MATCH.name))))
  File "/usr/local/lib/python3.6/site-packages/pyknow/operator.py", line 45, in __from_operator2
    "A ConditionalElement can't be used as an operator condition.")
TypeError: A ConditionalElement can't be used as an operator condition.

Note: If I match against a string it's working as follows:

@Rule(AND(Bottle(name=MATCH.name),
              Action(parameters=MATCH.params & CONTAINS("bottle"))))
nilp0inter commented 6 years ago

The only way of doing this currently is using TEST.

@Rule(
    Bottle(name=MATCH.name),
    Actions(parameters=MATCH.params),
    TEST(lambda name, params: name in params))

In future versions CONTAINS will support a ConditionalElement, but now is not possible due to the lack of support of parameters in P().

Behery commented 6 years ago

works like a charm ... thanks :)