List Prolog:使用递归在多个列表上成对兼容
所以我有一个谓词:List Prolog:使用递归在多个列表上成对兼容,list,recursion,prolog,meta-predicate,List,Recursion,Prolog,Meta Predicate,所以我有一个谓词: compatible([],_). compatible(_,[]). compatible([HA|TA],[HB|TB]) :- HA \= HB, compatible(TA,TB). 它当前接受两个列表,并确定它们是否成对兼容,如果是,则返回true,如果不是,则返回false 例如: ?- compatible([8,2,6,3,67],[7,4,7,4,3]). true ?- compatible([8,2,6,3,3],[7,4,7,4,
compatible([],_).
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
它当前接受两个列表,并确定它们是否成对兼容,如果是,则返回true,如果不是,则返回false
例如:
?- compatible([8,2,6,3,67],[7,4,7,4,3]).
true
?- compatible([8,2,6,3,3],[7,4,7,4,3]).
false.
第二次呼叫返回false,因为3在两个列表的第5位
我的问题是如何修改这个谓词,使其递归地检查两个以上的列表。谓词可能会检查包含1、2、3、4、5甚至无限列表的列表。如果任何列表彼此不兼容,则返回false
因此,我可以检查如下3个列表:
let Y = [[8,2,6,3,67],[7,4,7,4,3],[1,3,42,1,52]]
then...
?- compatible(Y).
true
let Z = [[8,2,6,3,67],[7,4,7,4,3],[1,3,6,1,52]]
then...
?- compatible(Z).
false.
如果第二次调用失败,因为6位于列表1和3的第三位置。如果所有子列表的长度相同,并且元素始终为整数,则可以根据以下两个谓词定义问题: 根据此定义,您的示例如下:
?- compatible([[8,2,6,3,67],[7,4,7,4,3],[1,3,42,1,52]]).
true.
?- compatible([[8,2,6,3,67],[7,4,7,4,3],[1,3,6,1,52]]).
false.
如果子列表可以有不同的长度,您应该首先找到最短的,然后将其余的剪切到该长度
如果列表的元素可以是任意的Prolog术语,请看一看。简言之:
all_different_terms([]).
all_different_terms([H|T]) :-
maplist(dif(H), T),
all_different_terms(T).
注意使用dif/2
而不是\=/2
?- compatible_terms([[a,b,c],[d,e,f],[g,h,i]]).
true.
?- compatible_terms([[a,b,c],[d,e,f],[a,h,i]]).
false.
所有不同的\u术语/1
的定义也应该让您了解如何实现您的初始建议,重用您已经定义的谓词compatible/2
:
all_compatible([]).
all_compatible([H|T]) :-
maplist(compatible(H), T),
all_compatible(T).
这是一种非递归的方法
compatible([],_).
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
pairs(ListOfLists,One,Two):-
select(One,ListOfLists,L1),
select(Two,L1,L2).
test(ListOfLists):-
forall(pairs(ListOfLists,A,B),compatible(A,B)).
否则:
compatible([],_).
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
HA \= HB,
compatible(TA,TB).
compatible_one_many(_,[]).
compatible_one_many(One,Many):-
Many=[H|T],
compatible(One,H),
compatible_one_many(One,T).
test_recursive([]).
test_recursive(ListOfLists):-
ListOfLists=[H|T],
compatible_one_many(H,T),
test_recursive(T).
您可以使用
test/2
和test\u recursive/2
来检查列表是否兼容。编写递归序言代码可能是一个很好的练习,非常有趣,是一项有意义的活动,但是正确掌握递归的细节可能很难,尤其是对于新手来说
幸运的是,还有另一种方法;它可以将您提升到一个更高的层次,以一种更惯用的逻辑编程方式,使您能够立即做很多事情
对于你的“成对兼容”问题,考虑结合使用<代码>兼容/ 1 谓词,你已经拥有了!以下是方法:
?- pairwise(compatible, [[8,2,6,3,67],[7,4,7,4,3],[1,3, 6,1,52]]). false. % finite failure, as expected ?- pairwise(compatible, [[8,2,6,3,67],[7,4,7,4,3],[1,3,42,1,52]]). true % succeeds, as expected ; true % (1st redundant answer) ; true % (2nd redundant answer) ; true % (3rd redundant answer) ; true % (4th redundant answer) ; true % (5th redundant answer) ; true % (6th redundant answer) ; true. % (7th redundant answer) 这两条罪魁祸首条款将突出显示。使用公共位置优先参数索引(以及上面的定义),Prolog无法推断某些目标可以决定性地成功现在有一个更重要的问题:你只需要处理数字(整数)吗?或者列表的元素可以是其他序言术语吗?你用的是什么序言?(我这样问是因为我无法识别
let Y=…
语法)这些只是int,是SWI-Prolog,“let Y=”只是表示列表的伪代码。谢谢你帮我解决这个问题!我真的很感谢你们和“用户27815”,你们终于解决了我一周的问题!谢谢大家!@jankyCoder我强烈建议您将transpose+all_与手动编码的递归进行比较。如果你能写更少的代码,那么写更多的代码从来都不是一个好主意:)@jankyCoder我的问题是,“你为什么坚持要写递归谓词”仍然有效。不知何故,这是一个要求吗?我想我认为这是实现这一点的最佳方式,但我对Prolog相当陌生,所以这只是一个最好的猜测。我已经开悟了@jankyCoder我真的不认为有什么“最好”的方法可以做任何事情(当然,除非你是一个Pythonista)。但正如我所说的,少写是好的,因为它花费的时间更少,犯愚蠢错误的机会也更少。pairs/3返回相同的交换列表:它是(无用的)O^2。这个问题包含了“甚至可能是无限列表”的说法。“甚至可能是无限列表”不是一个经过深思熟虑的要求,你不这么认为吗?我可能是错的,但是对于无限多的列表,你永远不可能最终知道这些列表是兼容的,只是它们不是。我想知道,只要无限多个列表是兼容的,人们会如何使用一个永远持续的谓词:在一个单独的线程中?如果您想避免@capelical所提到的问题,您的对/3
不必要的O^2复杂性,在我的回答中,请看一下所有不同的\u术语/1
的定义:您可以使用相同的框架编写谓词所有兼容的/1
,只需使用兼容的/2
而不是dif/2
。在这种情况下,pairs/3并不完美。
compatible([],_).
compatible(_,[]).
compatible([HA|TA],[HB|TB]) :-
dif(HA,HB), % unlike `(\=)/2`, `dif/2` is sound
compatible(TA,TB).
compatible([],_).
compatible([X|Xs],Ys) :-
compatible_(Ys,X,Xs).
compatible_([],_,_).
compatible_([Y|Ys],X,Xs) :-
dif(X,Y),
compatible(Xs,Ys).
?- pairwise(compatible, [[8,2,6,3,67],[7,4,7,4,3],[1,3, 6,1,52]]).
false. % SAME : finitely fails
?- pairwise(compatible, [[8,2,6,3,67],[7,4,7,4,3],[1,3,42,1,52]]).
true. % BETTER: succeeds deterministically