假设我有一个谓词foo/2
,它定义了第一个和第二个参数之间的关系。
改变foo/2
实施的最惯用和最有效的方式是:
如果它的两个参数都是基础的,它就像以前一样(如果关系成立则成功,否则失败)。
如果两个参数中的一个(或两个)都是免费的,那么它就会限制"这两个论点,以便当它们接地时,将检查关系。
换句话说,如何正确实现dif/2
所展示的行为,但具有任何类型的用户定义关系?
listing(dif/2).
没什么帮助。
答案 0 :(得分:3)
不同的Prolog实现提供了不同的功能来实现这一目标。该机制被称为 coroutining ,延迟目标,约束,您的Prolog系统手册将提供更多信息。
以下是两种变体,可在SICStus Prolog以及其他一些系统中找到。
block/1
指令在SICStus Prolog(可能还有其他一些系统)中,可以通过声明block
declaration获得将用户定义的谓词提升为这种约束版本的一种方法。
有趣的是,这个不需要对谓词本身进行任何更改!
假设您使用非单调dif/2
谓词来获得(\=)/2
的不纯版本:
madif(X, Y) :- X \= Y.
然后您可以将其转换为延迟版本,例如:
:- block madif(-, ?), madif(?, -). madif(X, Y) :- X \= Y.
示例查询和答案:
| ?- madif(a, b). yes | ?- madif(a, X). user:madif(a,X) ? ; no | ?- madif(a, X), X = b. X = b ? ; no | ?- madif(X, Y). user:madif(X,Y) ? ; no
根据需要,目标的评估会延迟,直到两个参数被实例化。
when/2
使用SICStus Prolog(以及提供此功能的其他系统)实现此目的的第二种方法是使用when/2
。这需要更改谓词本身。
例如,使用when/2
,您可以像这样实现madif/2
:
madif(X, Y) :- when((ground(X), ground(Y)), X \= Y).
示例查询和答案:
| ?- madif(X, a). prolog:trig_ground(X,[],[X],_A,_A), prolog:when(_A,(ground(X),ground(a)),user:(X\=a)) ? ; no | ?- madif(X, a), X = b. X = b ? ; no
答案 1 :(得分:3)
首先,
......而不是实施者。通常这会被忽略 - 在现有的约束实现中也是如此。它表明。所以这里是最重要的方面。
显然这应该成立。产生干净的错误总是更好,主要是实例化错误,更好地永远挣扎,甚至更好地永远循环而不是错误地失败。如果一切都中断,您可以使用freeze(_, G_0)
包裹您的尝试。请注意,您确实需要一个工作来实际看到这样的挣扎目标。 SICStus有一个顶级的 1 ,在SWI中你需要将查询包装为call_residue_vars(Query_0, Vs)
以查看所有附加的约束。
接下来,您需要确保您的约束尽可能确保一致性。有许多一致性概念,如域和边界一致性。要明确要求,请考虑difgrn/2
并将其与内置dif/2
进行比较:
difgrn(X, Y) :-
when((ground(X), ground(Y)), X \== Y).
| ?- difgrn(X, X).
prolog:trig_ground(X,[],[X],_A,_B),
prolog:trig_ground(X,[],[X],_A,_C),
prolog:trig_and(_C,[],_A,_B,_A),
prolog:when(_A,(ground(X),ground(X)),user:(X\==X)) ? ;
no
| ?- dif(X, X).
no
| ?- difgrn([], [_]).
prolog:trig_ground(_A,[],[_A],_B,_C),
prolog:trig_and(_C,[],_B,1,_B),
prolog:when(_B,(ground([]),ground([_A])),user:([]\==[_A]))
| ?- dif([], [_]).
yes
完全实施dif/2
的一种方法是使用非常特殊的条件(?=)/2
:
difwh(X,Y) :- when(?=(X,Y), X\==Y).
应该尽可能地回答你的问题:
换句话说,如何正确实现dif / 2所展示的行为,但是具有任何类型的用户定义关系?
但不幸的是,这并没有延伸到其他任何事情。
如果考虑各种约束之间的一致性,情况会变得更加复杂。想想X in 1..2, dif(X, 1), dif(X, 2)
。
(因为缺少一个更好的词。)有时候你想在顶层很好地看到你的约束 - 最好的方法是将它们表示为自己将重新建立代表答案所需的确切状态的目标。
见上面trig_ground
个答案,肯定可以稍微美化一下。
与回答预测相同,但可以在任何时间点通过frozen/2
或copy_term/3
投放。
这对于诊断和循环检查很有用。
对于纯语法术语,有subsumes_term/2
忽略约束。执行有效测试的先决条件是将每个涉及的变量连接到实际约束。考虑目标freeze(X, Y = a)
并想象一些以Y
作为参数的包含检查。如果Y
不再附加到信息上(通常是freeze/2
的当前实现),您会得出错误的结论:Y
包含b
。< / p>
注意dif/2
的实际例子,这是有史以来的第一个约束(1972年,Prolog 0)。更精细的描述给出了Michel van Caneghem在L'anatomie de Prolog,InterÉditions1986和Lee Naish的论文中关于MU-Prolog。
1半真。对于library(clpfd)
,您需要assert(clpfd:full_answer).