在编写纯关系型prolog程序时,使用仔细放置的剪切是否可以?

在编写纯关系型prolog程序时,使用仔细放置的剪切是否可以?,prolog,prolog-cut,clp,Prolog,Prolog Cut,Clp,我正在尝试编写一个关系prolog程序来管理一个键、值存储。最初的代码取自我在互联网上找到的一些课堂幻灯片(参见:使用数据结构幻灯片) 这段代码允许用同一个键添加多个值——这对我来说没问题。但是,它也会两次添加相同的键、值对,例如 ?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X). D = [], D2 = [p(a, 1)], D3 = [p(a, 1), p(a, 1)], X = 1 D3

我正在尝试编写一个关系prolog程序来管理一个键、值存储。最初的代码取自我在互联网上找到的一些课堂幻灯片(参见:使用数据结构幻灯片)

这段代码允许用同一个键添加多个值——这对我来说没问题。但是,它也会两次添加相同的键、值对,例如

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X).
D = [],
D2 = [p(a, 1)],
D3 = [p(a, 1), p(a, 1)],
X = 1 
D3包括p(a,1)两次

为了确保这不会发生,我添加了以下代码;为了确保回溯不会找到替代的addkey子句,我在第一个子句的末尾添加了一个cut

对于纯关系型程序来说,这是公平的游戏吗?或者是确保不添加重复的键、值对的更好方法吗?而不使用剪切

newdic([]).
addkey(D0,K,I,D0) :- lookup(D0, K, I), !.   % if the key already do nothing
addkey(D0,K,I,D) :- D = [p(K,I)|D0].
delkey([],_,[]).
delkey([p(K,_)|D],K,D).
delkey([p(K0,I)|D0],K,[p(K0,I)|D]) :-
    dif(K, K0), delkey(D0,K,D).
这导致以下情况:

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), lookup(D3, a, X).
D = [],
D2 = D3, D3 = [p(a, 1)],
X = 1.
不,还有更多的解决方案可用——程序会立即返回

非常感谢您的任何建议

丹尼尔

注意:作为旁白:如果我为同一关键点添加不同的值,剪切确实允许回溯以识别同一关键点的第二个值:

?- newdic(D), addkey(D, a, 1, D2), addkey(D2, a, 1, D3), addkey(D3, a, 2, D4), lookup(D4, a, X).
D = [],
D2 = D3, D3 = [p(a, 1)],
D4 = [p(a, 2), p(a, 1)],
X = 2 ;
D = [],
D2 = D3, D3 = [p(a, 1)],
D4 = [p(a, 2), p(a, 1)],
X = 1.

您可以使用if-then-else而不是cut:

addkey(D0,K,I,D0) :-
  ( lookup(D0, K, I) ->
    D = D0 % if the key already [exists] do nothing
  ; D = [p(K,I)|D0] ).

SWI Prolog具有用于处理键值对和关联的库谓词。我没有仔细观察它们,看看有什么可以与你的情况相匹配,但有些事情要考虑。 如果您想推出自己的解决方案,可以递归地编写
addkey/4
并维护关系行为:

addkey([], K, V, [p(K,V)]).             % Add to empty dict
addkey([p(K,V)|T], K, _, [p(K,V)|T]).   % Don't add
addkey([p(K,V)|T], Kadd, Vadd, [p(K,V)|TK]) :-
    dif(Kadd, K),
    addkey(T, Kadd, Vadd, TK).

如果密钥是唯一的,则此实现会添加。如果您使用不同的值尝试相同的键(这通常是键值对字典的行为),它将忽略该加法并返回相同的字典。您可以很容易地增强它,使其具有键值对的唯一性。当然,您正在使用的序言需要包含
dif/2
,或者您需要滚动自己的
dif/2

谢谢你的及时回复。这个if-then-else是否符合关系…@user2193970“if-then-else”等同于使用一个cut,在其行为中不再是“关系”的。表达式,
p1->p2;p3的行为如下:
(p1,!,p2);p3
。它在视觉上可能更容易被接受,但在行为上却并非如此。if-then-else的关系版本是。不仅在视觉/美学上,它也更难被误用。剪切主要用于避免修复逻辑问题。我在swi prolog中找不到\u3——我可以用其他构造写出它吗?@user2193970不幸的是,
if\u3
不是标准谓词。它是在我提供的链接中定义的。如果您只希望它成功一次,您可以使用类似
的方法(查找(D0,K,I))
。您对当前的答案真的满意吗?毕竟,你问的有些不同。谢谢。我对自己尝试处理关系prolog感兴趣;但既然您提到了它,我可能很快就会转而使用swi prolog中的assoc库——它更成熟,也可能更具可扩展性。
addkey([], K, V, [p(K,V)]).             % Add to empty dict
addkey([p(K,V)|T], K, _, [p(K,V)|T]).   % Don't add
addkey([p(K,V)|T], Kadd, Vadd, [p(K,V)|TK]) :-
    dif(Kadd, K),
    addkey(T, Kadd, Vadd, TK).