用于检查"变量"是否空闲或已经绑定的谓词应该改变用于获得其他"变量"的正确统一的策略(即加速,或者可以导出它们).对于动态谓词也是如此 - 它们可以用来加速某些事情,但它们不应该被用作改变某事物行为的触发器.
我想知道为什么会这样.为什么检查是否已将某些内容定义为其他内容是不好的做法?你认为这是不好的做法吗?还有其他选择可以"更好地练习".
这是我的解决方案:
% ================================
% Ensures that all variables are unique.
% ================================
% Base case: Assigned variables unique values
used([], Nin, Nin).
% Have already assigned a value to this variable
used([A|B], Nin, Nout) :-
integer(A), % <----------------- THIS IS THE LINE IN QUESTION
helper(B,Nin,Nout).
% Have not assigned a value to this variable yet
% Assign it and remove it from the list.
used( [A|B] , Nin, Nout) :-
member(A,Nin),
delete(Nin,A,Temp),
helper(B,Temp,Nout).
Run Code Online (Sandbox Code Playgroud)
像谓词的最根本的问题integer/1
,atom/1
等等是他们不单调.
以?- integer(5).
成功为例.但是更普遍的目标?- integer(X).
,失败了!
对于声明性调试和自动生成的解释,我们希望如果目标成功,那么该目标的每次推广都不会失败.
"正确"(即,如果你想要具有声明性意义的好单调谓词)要做的事情是在查询上integer/1
引发实例化错误,例如?- integer(X).
理由是它目前没有足够的信息来回答问题.而不是integer/1
,你应该使用must_be/2
from library(error)
来获得这种声音行为:
?- must_be(integer, X).
ERROR: Arguments are not sufficiently instantiated
Run Code Online (Sandbox Code Playgroud)
must_be/2
表现单调,这通常是一个不错的属性.
扩展ony的评论:问题是(至少如果上面的样本结果是正确的)你的谓词不再是真正的关系,因为目标现在不是可交换的:?- X = 0, X = Y, addUnique([X,Y,3],3).
成功,但只是交换目标的顺序不会产生相同的结果,因为?- X = Y, addUnique([X,Y,3], 3), X = 0.
失败.
这种现象是使用元逻辑谓词的常见后果.这些问题的声明性解决方案是约束,例如参见dif/2
.它们是单调的,可交换的,通常更容易理解.