受到早期问题的启发,我试图实现一些能够枚举布尔表达式的可能性.但是,我在变量选择方面遇到了麻烦.这是我的预期结果:
?- eval(X^Y, R).
R = 0^0;
R = 0^1;
R = 1^0;
R = 1^1;
no.
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
:- 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).
Run Code Online (Sandbox Code Playgroud)
即使对于这个简单的情况,这已经不能做我想要的了:
?- 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)) .
Run Code Online (Sandbox Code Playgroud)
所以,我可以看到的问题是什么在这里,这是通过该方法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.
Run Code Online (Sandbox Code Playgroud)
在这种情况下,这将是代码:
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).
Run Code Online (Sandbox Code Playgroud)
请记住,我仍然喜欢它与递归公式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
代码中的逻辑外谓词,就没有希望保持其逻辑纯度和单调性.瞄准干净的表示以保留这些属性.
有时,使用默认表示是不可避免的,例如,因为您希望为用户提供更容易的输入.在这种情况下,目标是在开始实际推理之前快速将它们转换为干净的.