Prolog最佳实践:检查变量是否已绑定.

six*_*ude 4 prolog

我把这个解决方案发布到一个问题,但是留下了评论说:

用于检查"变量"是否空闲或已经绑定的谓词应该改变用于获得其他"变量"的正确统一的策略(即加速,或者可以导出它们).对于动态谓词也是如此 - 它们可以用来加速某些事情,但它们不应该被用作改变某事物行为的触发器.

我想知道为什么会这样.为什么检查是否已将某些内容定义为其他内容是不好的做法?你认为这是不好的做法吗?还有其他选择可以"更好地练习".

这是我的解决方案:

% ================================
% 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)

mat*_*mat 8

像谓词的最根本的问题integer/1,atom/1等等是他们不单调.

?- integer(5).成功为例.但是更普遍的目标?- integer(X).,失败了!

对于声明性调试和自动生成的解释,我们希望如果目标成功,那么该目标的每次推广都不会失败.

"正确"(即,如果你想要具有声明性意义的好单调谓词)要做的事情是在查询上integer/1引发实例化错误,例如?- integer(X).理由是它目前没有足够的信息来回答问题.而不是integer/1,你应该使用must_be/2from 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.它们是单调的,可交换的,通常更容易理解.