受到早期问题的启发,我试图实现一些能够枚举布尔表达式的可能性.但是,我在变量选择方面遇到了麻烦.这是我的预期结果:
?- eval(X^Y, R). R = 0^0; R = 0^1; R = 1^0; R = 1^1; no.
这是我的代码:
:- op(200, yfx, ^). split(V, R) :- var(V), R = 0. split(V, R) :- var(V), R = 1. split(X ^ Y, XP ^ YP) :- split(X, XP), split(Y, YP).
即使对于这个简单的情况,这已经不能做我想要的了:
?- split(Y, R). R = 0 ; R = 1 ; Y = _G269^_G270, R = 0^0 ; Y = _G269^_G270, R = 0^1 ; Y = _G269^ (_G275^_G276), R = 0^ (0^0) ; Y = _G269^ (_G275^_G276), R = 0^ (0^1) ; Y = _G269^ (_G275^ (_G281^_G282)), R = 0^ (0^ (0^0)) .
所以,我可以看到的问题是什么在这里,这是通过该方法split(Y, YP)
的Prolog已用尽前两个条款,因此在卷起split(X^Y, ...)
再次,统一我Y
用X'^Y'
,基本上是.我只是不确定我需要做什么来关闭那条路径,除非在我有结构的一开始^/2
.
我也喜欢这个与嵌套结构一起工作,所以我不能只是消除分支的递归处理.
编辑:没有运营商
如果op/3
困扰你,请考虑以下配方:
eval(and(X,Y), R). R = and(0,0); R = and(0,1); R = and(1,0); R = and(1,1); no.
在这种情况下,这将是代码:
split(V, R) :- var(V), R = 0. split(V, R) :- var(V), R = 1. split(and(X,Y), and(XP,YP)) :- split(X, XP), split(Y, YP).
请记住,我仍然喜欢它与递归公式and(and(X,Y),and(Y,Z))
等工作.
这种情况下的核心问题是您用来表示布尔表达式的默认表示.
通过"defaulty"我的意思是,你不能清楚地分辨由案件模式匹配:在你的情况,一个变量V
可以指任
一个命题常数0
和 1
,或
形式的复合表达A^B
.
由于这个缺点,您无法在程序中干净地表达"变量X
仅代表两个命题常量之一" 形式的约束.
声明性的出路是用干净的表现 ,而不是.
例如,假设我们任意使用v/1
来区分仅表示命题常量的变量,那么我们有:
v(X)
表示命题变量 X
A^B
表示复合表达.
显然,由于主要的算子和元素是不同的(v/1
相对(^)/2
),我们可以通过模式匹配来区分这些案例.
使用此新表示形式,您的代码段将变为:
split(v(V), V) :- V = 0. split(v(V), V) :- V = 1. split(X^Y, XP ^ YP) :- split(X, XP), split(Y, YP).
示例查询:
?- split(v(X)^v(Y), R). X = Y, Y = 0, R = 0^0 ; X = 0, Y = 1, R = 0^1 ; X = 1, Y = 0, R = 1^0 ; X = Y, Y = 1, R = 1^1.
请注意,这仍然适用于所有方向,也是最常见的情况:
?- split(Expr, R). Expr = v(0), R = 0 ; Expr = v(1), R = 1 ; Expr = v(0)^v(0), R = 0^0 ; Expr = v(0)^v(1), R = 0^1 ; etc.
根据经验,一旦你必须使用var/1
代码中的逻辑外谓词,就没有希望保持其逻辑纯度和单调性.瞄准干净的表示以保留这些属性.
有时,使用默认表示是不可避免的,例如,因为您希望为用户提供更容易的输入.在这种情况下,目标是在开始实际推理之前快速将它们转换为干净的.