我正在尝试创建一个带有列表对的谓词,如果它在列表中找到了键,它将从列表中删除该项并返回其余项。但是,如果给定的密钥不存在,它还需要返回完整列表。
unmap(K, M1, M2):-
select(E, M1, MM1),
select(E, [(K, _)], K1),
unmap(MM1, K1, M2).
unmap(X, _, X).
跟:
unmap(key1, [(key1, value1),(key2, value2),(key3, value3)], R).
结果:
R = [(key2, value2), (key3, value3)]
工作,但这是一个问题。我试图让它返回相同的列表,如果key1不存在则给出。这是它的回报:
通话:
unmap(key4, [(key1, value1),(key2, value2),(key3, value3)], R).
返回:
R = key4
我认为这与我的终止规则有关,但我不确定如何修复它。非常感谢所有可以提供帮助的人。
答案 0 :(得分:2)
当然,你可以用logical-purity做到!以下是......
让我们调用实际关系unmap/3
。这是一个更强烈的描述性名称。 pairs_key_unmapped/3
只是unmap(Key,Ps0,Ps) :-
pairs_key_unmapped(Ps0,Key,Ps).
的包装器:
pairs_key_unmapped/3
if_/3
的实施基于谓词=/3
和equal_truth/3
(又名pairs_key_unmapped([],_,[]).
pairs_key_unmapped([P|Ps],K,Us) :-
P = (K0,_),
if_(K0=K, Ps=Us, (Us=[P|Us0],pairs_key_unmapped(Ps,K,Us0))).
),由answer中的@false定义为& #34; Prolog union for A U B U C":
Key
让我们运行一些查询!
?- unmap(key1,[(key1,value1),(key2,value2),(key3,value3)],Ps). Ps = [(key2,value2),(key3,value3)]. % succeeds deterministically ?- unmap(key4,[(key1,value1),(key2,value2),(key3,value3)],Ps). Ps = [(key1,value1),(key2,value2),(key3,value3)]. % succeeds deterministically
让我们尝尝不同的事情......如果在Ps0
Ps0
发生两次会怎样?
?- unmap(key1,[(key1,x),(key1,y)],Ps). % only the 1st occurrence is removed Ps = [(key1,y)]. % succeeds deterministically
如果Ps
未知,但{{1}} 已知,该怎么办?
?- unmap(key4,Ps0,[(key1,value1),(key2,value2),(key3,value3)]). Ps0 = [(key4,_A), (key1,value1),(key2,value2),(key3,value3)] ; Ps0 = [(key1,value1),(key4,_A), (key2,value2),(key3,value3)] ; Ps0 = [(key1,value1),(key2,value2),(key4,_A), (key3,value3)] ; Ps0 = [(key1,value1),(key2,value2),(key3,value3) ] ; Ps0 = [(key1,value1),(key2,value2),(key3,value3),(key4,_A) ] ; false.
更通用的内容怎么样?
?- unmap(Key,Ps0,[_,_]). Ps0 = [(Key,_A),_B, _C ] ; Ps0 = [(_A,_B), (Key,_C), _D ], dif(_A,Key) ; Ps0 = [(_A,_B), (_C,_D) ], dif(_A,Key), dif(_C,Key) ; Ps0 = [(_A,_B), (_C,_D), (Key,_E)], dif(_A,Key), dif(_C,Key) ; false.
最常见的查询给出了什么答案?
?- unmap(Key,Ps0,Ps). Ps0 = [], Ps = [] ; Ps0 = [(Key,_A)|Ps] ; Ps0 = [(_A,_B)], Ps = [(_A,_B)], dif(_A,Key) ; Ps0 = [(_A,_B),(Key,_C)|_Z], Ps = [(_A,_B)|_Z], dif(_A,Key) ; Ps0 = [(_A,_B),(_C,_D)], Ps = [(_A,_B),(_C,_D)], dif(_A,Key), dif(_C,Key) ...
答案 1 :(得分:1)
问题在于您的基本情况:
unmap(X, _, X).
如果你的主谓词失败(找不到键),它将恢复为基本情况,它将仅使用键(第一个参数)实例化你的结果(第三个参数)。你的基本情况应该是:
unmap(_, X, X).
将使用原始列表(第二个参数)实例化结果(第三个参数)。
请注意,main子句可以更简单(这可以在GNU或SWI prolog中使用):
unmap(K, M, R):-
select((K, _), M, M1),
unmap(K, M1, R), !.
如果第一个子句成功,剪切会阻止回溯到基本案例。
在SWI Prolog中,delete/3
谓词对您有利:
unmap(K, M, R) :-
delete(M, (K,_), R), !.
delete/3
在GNU Prolog中更严格,在这种情况下不起作用。
答案 2 :(得分:1)
这不是问题的答案,而是一种更简单的攻击方式,不使用'select'(或任何其他内置谓词),只使用递归。
考虑到输出列表只是与键不匹配的项列表,您需要2个主要子句,并围绕列表进行迭代。密钥与列表头部匹配的密钥,以及不匹配的密钥。
unmap(_, [], []).
% head of the list matches key, do not add K/H to unmatched list (ie remove it)
unmap(K, [(H, _)|Tail], Unmatched) :-
H == K,
unmap(K, Tail, Unmatched).
% above rule fails, add H to unmatched list
unmap(K, [H|Tail], [H|Unmatched]) :-
unmap(K, Tail, Unmatched).
?- unmap(key1, [(key1, value1),(key2, value2),(key3, value3)], R).
R = [ (key2, value2), (key3, value3)] .
?- unmap(key4, [(key1, value1),(key2, value2),(key3, value3)], R).
R = [ (key1, value1), (key2, value2), (key3, value3)] .
因此,如果密钥不存在,它只是迭代添加所有列表项,因此输入和输出列表是相同的。