library(clpb)
目前在SICStus(原始版本)和SWI(按mat)中可用。让我很快来谈谈本质:
?- X = 1+1, sat(X), X = 1+1.
X = 1+1.
?- sat(X), X = 1+1.
false.
因此,这与library(clpfd)
的默认状态下存在的问题类似。
在这种情况下该怎么办?
更新:在mat的library(clpfd)
中,现在有了用于此目的的函子# /1
。理想情况下,伴随着运算符声明op(150,fx,#)
,我们现在可以写:
?- X = 1+1, #X #= Y.
ERROR: Type error: `integer' expected, found `1+1' (a compound)
为了确保完整的代数性质,必须声明:
:- set_prolog_flag(clpfd_monotonic, true).
现在,不明确的变量(因此,要么是整数,要么是表达式)会产生实例化错误:
?- 1 + 1 #= Y.
ERROR: Arguments are not sufficiently instantiated
?- 1 + 1 #= #Y.
Y = 2.
在这种情况下该怎么办?
同时,library(clpb)
也保证了类似于library(clpz)
/library(clfd)
的单调性。在这种执行模式中,显式变量必须使用(v)/1
进行修饰。
?- current_prolog_flag(clpb_monotonic,B).
B = false. % the default
?- sat(X).
X = 1.
?- set_prolog_flag(clpb_monotonic,true).
true.
?- sat(X).
ERROR: Arguments are not sufficiently instantiated
?- sat(v(X)).
X = 1.
在Scryer中,说:
?- use_module(library(clpb)).
true.
?- asserta(clpb:monotonic).
true.
?- sat(X).
error(instantiation_error,instantiation_error(unknown(_67),1)).
?- sat(v(X)).
X = 1.
是,CLP(FD)和CLP(B)中相同:
情况
CLP(FD),(+)/2在有限域中充当加法:
?- X = 1+1, X #= 2.
X = 1+1.
?- X #= 2.
X = 2
?- X #= 2, X = 1+1.
false.
CLP(B),(+)/2在布尔域中充当析取:
?- X = 1+1, sat(X)
X = 1+1
?- sat(X)
X = 1
?- sat(X), X = 1+1.
false
但现在要注意,这样的事情已经在普通的序言中发生了:
?- X = 3, X = 4.
X = 3.
?- X = 4, X = 3.
false.
问题
那么我们应该告诉学生什么呢?我不认为CLP(FD)或CLP(B)应对此负责。
它更根深蒂固,而且不可能陷入(=)/2,因此它所做的不仅仅是verify_attribute/3。
在理想世界中,(=)/2用代数运算,X=1+1不会失败,系统会看到1+1等于2(FD情况)分别为1+1等于1(B情况)。
但为此,Prolog系统将需要类型作为启动,否则(=)/2不能解释(+)/2,它有两种不同的解释在我们的例子中。
解决方案
解决方案是在需要特定类型的情况下避免使用(=)/2。在此我推荐阅读:
使用ECLiPSe的约束逻辑编程
Krzysztof R.Apt和Mark Wallace,
2006年5月16日,全文PDF
上面的文章稍微强调了散列符号(#)作为运算符(=)/2、(<)/2等的前缀的动机。它已经是一种类型注释了。本文中还有另一个前缀,即美元符号($)。
在ECLiPSe-Prolog中,散列符号(#)表示约束整数/1,美元符号($)表示约束实数/1。这些约束也可以独立使用,如以下示例所示:
?- integers([X,Y]), X = 3, Y = 4.5.
No
?- reals(X), X = [1,2.1,a].
No
回到(=)/2的非交换性问题。虽然(=)/2是不可交换的,但(#=)/2及其布尔兄弟当然是可交换的。我们有:
CLP(FD),(+)/2在有限域中充当加法,与(#=)/2交换存在:
?- X #= 1+1, X #= 2.
X = 2
?- X #= 2, X #= 1+1.
X = 2
CLP(B),(+)/2在布尔域中充当析取,并且具有sat/1和(=:=)/2的交换性:
?- sat(X=:=1+1), sat(X).
X = 1.
?- sat(X), sat(X=:=1+1).
X = 1
verify_attribute/3挂钩只会唤醒约束,这些约束可能会使Herbrand域统一失败。但是,在将术语分配给Prolog变量之前,它们无法实时评估术语。
只有唤醒的约束可能会将值分配给其他变量。但例如,verify_atribute/3的当前SICStus规范甚至建议不要直接执行此操作,而只在延续队列中执行。请参阅最近的SWI Prolog小组讨论。
长话短说:永远不要忘记,(=)/1只适用于Prolog中的Herbrand域,即使我们使用了约束。我并不是说Prolog系统不能以不同的方式工作,但这就是群体或Prolog系统的艺术状态。
再见