conda 和 condu 的语义特别重视每个子句的头部,但是建立在它们之上的 core.logic 的模式匹配宏将主体合并到头部中。这意味着在决定选择哪一行时,考虑的是主体位置中的每个表达式,而不仅仅是头部位置中的表达式。这是因为在整个子句都被一个新的表达式包裹起来以绑定在模式中出现的隐式指定的 lvars。
为了说明:
`
(matcha ['a]
[['a] u#]
[['a] s#])
;; 展开为
(conda
[(fresh [] (== 'a 'a) u#)]
[(fresh [] (== 'a 'a) s#)])
;; 这与
(conda
[(== 'a 'a) u#]
[(== 'a 'a) s#])
`
理论上,我们可以设计一个新的系统来结合 conda 的语义与模式匹配。至少,我认为这些有问题的宏应该在它们的文档字符串中带有警告,说明这种语义差异。
我怀疑这也会使“第三条诫命”警告适用于整个行,而不仅仅是头部/问题,但我还没有调查这个问题。
以下是一个展示意义差异的示例:
`
;; 这不会成功,因为我们承诺了第一行,
;; 因为问题成功,但在主体中失败。
(run* [q]
(conda
[(== 'a 'a) u#]
[(== 'a 'a) s#]))
;; => ()
;; 这会成功,因为整个行被用来确定要承诺哪一行,
;; 而不仅仅是头部模式匹配子句。所以当第一行失败时,
;; 会尝试第二行。
(run* [q]
(matcha ['a]
[['a] u#]
[['a] s#]))
;; => (_0)
`