两种不同定义的并集规则

时间:2019-12-10 16:40:27

标签: clips

我希望在我尝试搜索已经提出的问题之前没有问过这个问题。我正在尝试编写一条规则,该规则将检查在一个deftemplate中定义的两个不同插槽是否都存在于另一个deftemplate的多插槽中。例如:

(deftemplate manifest
    (slot origin (type SYMBOL))
    (slot destination (type SYMBOL))
    (slot pkgsize (type INTEGER))
    (slot priority (type INTEGER))
    (slot zone (type SYMBOL) (default UNKNOWN))
)   
(deftemplate shipzone
    (slot zonename (type SYMBOL))
    (multislot cities (type SYMBOL))
)

(deffacts load-data
    (manifest (origin CHI) (destination DET) (pkgsize 10) (priority 1))
    (manifest (origin ATL) (destination WAS) (pkgsize 8) (priority 2))
    (manifest (origin CHI) (destination WAS) (pkgsize 15) (priority 1))
    (shipzone (zonename ZONEA) (cities CHI DET NYC BOS))
    (shipzone (zonename ZONEB) (cities ATL WAS NYC))
    (shipzone (zonename ZONEC) (cities CHI WAS BOS))
)

(defrule city-group
    ?f <- (manifest (origin ?x1) (destination ?x2) (zone UNKNOWN))
    (shipzone (zonename ?zname) (cities $?x1 $?x2))
    =>
    (modify ?f (zone ?zname))
)

给出以下错误:

CLIPS> (clear)
CLIPS> (load testgroup.clp)

[ANALYSIS3] testgroup.clp, Line 29: Variable ?x1 is used as both a single and multifield variable in the LHS.

ERROR:
(defrule MAIN::city-group
   ?f <- (manifest (origin ?x1) (destination ?x2))
   (shipzone (zonename ?zname) (cities $?x1 $?x2))
   =>
   (modify ?f (zone ?zname)))
%%$*
FALSE
CLIPS>

我在做什么错,还是有更好的方法来解决这个问题?

1 个答案:

答案 0 :(得分:1)

在模式中绑定变量时,必须始终绑定到单字段或多字段变量。当您最初以 manifest 模式绑定单变量?x1和?x2时,它们将绑定到一个值。当您在 shipzone 模式中绑定多字段变量 $?x1 $?x2 时,这些变量将被绑定到零个或多个值。因为在多个位置绑定的变量必须具有相同的值,所以如果规则匹配, $?x1 $?x2 不可能有多个值,因此之所以将其视为错误,是因为该模式不太可能按照您认为的去做。

有几种方法可以重写此规则。如果您希望城市时段以起源开头并以目的地结束并插入任意数量的城市,则可以重写规则这样,可以使用多字段通配符跳过中间的城市:

(defrule city-group
    ?f <- (manifest (origin ?x1) (destination ?x2) (zone UNKNOWN))
    (shipzone (zonename ?zname) (cities ?x1 $? ?x2))
    =>
    (modify ?f (zone ?zname))
)

如果城市可以在起源之前或在目的地之后,则您可以通过以下方式重写规则:

(defrule city-group
    ?f <- (manifest (origin ?x1) (destination ?x2) (zone UNKNOWN))
    (shipzone (zonename ?zname) (cities $? ?x1 $? ?x2 $?))
    =>
    (modify ?f (zone ?zname))
)

最后,如果要检查城市插槽中是否包含起源目的地(包括 >目的地发生在来源之前),您可以通过以下方式重写规则:

(defrule city-group
    ?f <- (manifest (origin ?x1) (destination ?x2) (zone UNKNOWN))
    (shipzone (zonename ?zname) (cities $?cities))
    (test (and (member$ ?x1 ?cities)
               (member$ ?x2 ?cities)))
    =>
    (modify ?f (zone ?zname))
)

test 条件元素中,将 member $ 函数传递给变量?cities 而不是 $?cities (尽管两者都可以)。这是允许的,因为变量不受此用法的限制。变量的值只是传递给函数。