我正在尝试编写一个管理密钥值存储的关系序言程序。初始代码取自我在互联网上找到的一些演讲幻灯片(http://people.eng.unimelb.edu.au/pstuckey/book/course.html - 请参阅:使用数据结构幻灯片)。
newdic([]).
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 = [p(a, 1)],
D3 = [p(a, 1), p(a, 1)],
X = 1
D3包括p(a,1)两次。
为确保不会发生这种情况,我添加了以下代码;并且为了确保回溯没有找到替代的addkey子句,我在第一个子句的末尾添加了一个剪切。
这是一个纯粹的关系程序的公平游戏 - 或者是更好的方法来确保不添加重复的键,值对 - 而不使用剪切。
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.
答案 0 :(得分:3)
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).
如果密钥是唯一的,则添加此实现。如果您尝试使用相同的键,即使具有不同的值(通常是键值对的字典行为),它也会忽略添加并返回相同的字典。您可以非常轻松地增强键值对的唯一性。当然,您正在使用的Prolog需要包含dif/2
,否则您需要推出自己的dif/2
。 :)
答案 1 :(得分:0)
您可以使用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] ).