我对Prolog很新,我需要一些小问题的帮助:
我正试图在两个列表中分割一对情侣列表。第一个列表包含具有给定键的所有对,第二个列表包含所有其他对象。
这是我到目前为止的代码:
splitList([],_,[],[]).
splitList([(A,X)|Rest], B, [Elem1|List1], [Elem2|List2]):-
(
A == B
->
Elem1 = (A,X),
splitList(Rest, B, List1, [Elem2|List2])
;
Elem2 = (A,X),
splitList(Rest, B, [Elem1|List1], List2)
).
当我尝试测试时,这就是我得到的:
[trace] [3] 143 ?- splitList([(1,yellow),(1,blue),(2,yellow),(2,blue)],1,X,Y).
Call: (37) splitList([ (1, yellow), (1, blue), (2, yellow), (2, blue)], 1, _G4821, _G4822) ? creep
Call: (38) 1==1 ? creep
Exit: (38) 1==1 ? creep
Call: (38) _G4928= (1, yellow) ? creep
Exit: (38) (1, yellow)= (1, yellow) ? creep
Call: (38) splitList([ (1, blue), (2, yellow), (2, blue)], 1, _G4929, [_G4931|_G4932]) ? creep
Call: (39) 1==1 ? creep
Exit: (39) 1==1 ? creep
Call: (39) _G4940= (1, blue) ? creep
Exit: (39) (1, blue)= (1, blue) ? creep
Call: (39) splitList([ (2, yellow), (2, blue)], 1, _G4941, [_G4931|_G4932]) ? creep
Call: (40) 2==1 ? creep
Fail: (40) 2==1 ? creep
Call: (40) _G4931= (2, yellow) ? creep
Exit: (40) (2, yellow)= (2, yellow) ? creep
Call: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep
Call: (41) 2==1 ? creep
Fail: (41) 2==1 ? creep
Call: (41) _G4958= (2, blue) ? creep
Exit: (41) (2, blue)= (2, blue) ? creep
Call: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep
Fail: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep
Fail: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep
Fail: (39) splitList([ (2, yellow), (2, blue)], 1, _G4941, [_G4931|_G4932]) ? creep
Fail: (38) splitList([ (1, blue), (2, yellow), (2, blue)], 1, _G4929, [_G4931|_G4932]) ? creep
Fail: (37) splitList([ (1, yellow), (1, blue), (2, yellow), (2, blue)], 1, _G4821, _G4822) ? creep
false.
明显的解决方案应该是X = [(1,黄色),(1,蓝色)]和Y = [(2,黄色),(2,蓝色)],但我得到假。 有人能告诉我我做错了吗?
提前致谢,
WALLE
答案 0 :(得分:6)
让我们看一下倒数第二个递归调用:
splitList([(2,blue)], 1, [Elem1|List1], [Elem2|List2])
^^^^^^^^^^^
在我标记的地方,您希望第一个列表仍然至少有一个元素。但是,最后一次递归调用无法满足此条件。这就是它失败的原因。跟踪的相关部分是:
# penultimate call:
Call: (40) splitList([ (2, blue)], 1, [_G4949|_G4950], _G4932) ? creep
[…]
# last call:
Call: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep
Fail: (41) splitList([], 1, [_G4949|_G4950], _G4959) ? creep
没有替代允许_G4949变量在最后一次调用中存在。
我会这样写:
splitList([], _, [], []).
splitList([(A, X)|Rest], A, [(A, X)|Rest1], Rest2) :-
splitList(Rest, A, Rest1, Rest2).
splitList([(A, X)|Rest], B, Rest1, [(A, X)|Rest2]) :-
A =\= B,
splitList(Rest, B, Rest1, Rest2).
顺便说一句,问题很好!
答案 1 :(得分:4)
问题出在基本情况中。 采取身体中的任何两种情况:
splitList(Rest, B, List1, [Elem2|List2])
当你到达最后时,除最后一个参数外,所有内容都正确统一,即Rest=[], B=_, List1=[]
...但[Elem2|List2]
未与[]
统一。
所以程序失败了。
尝试这样的事情(我没有运行过):
splitList([],_,[],[]).
splitList([(A,X)|Rest], A, [(A,X)|List1], List2):- !
splitList(Rest, A, List1, List2).
splitList([(B,X)|Rest], A, List1, [(B,X) | List2]):-
splitList(Rest, A, List1, List2).
答案 2 :(得分:1)
无需担心编写递归代码(以及关于正确编写代码)!
我们将splitList/4
定义如下(使用meta-predicate tpartition/4
,lambdas和(=)/3
):
:- use_module(library(lambda)).
splitList(KVs,K,Hits,Misses) :-
tpartition(K+\(K0,_)^(K0=K),KVs,Hits,Misses).
示例查询:
?- splitList([(1,yellow),(2,green),(1,blue),(2,red)],1,Hits,Misses). Hits = [(1,yellow),(1,blue)], Misses = [(2,green),(2,red)]. % deterministic
a lil'位更通用?
?- splitList([(1,yellow),(2,green),(1,blue),(2,red)],K,Hits,Misses). K=1 , Hits = [(1,yellow),(1,blue)], Misses = [(2, green),(2, red)] ; K=2 , Hits = [(2, green),(2, red)], Misses = [(1,yellow),(1,blue)] ; dif(K,1), dif(K,2), Hits = [] , Misses = [(1,yellow),(1,blue), (2, green),(2, red)].