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无法推断某些目标可以决定性地成功

  • 我们能应付吗?如果是这样,如何解决?程序性问题程序性解决方案,对吗?!是的,但我们需要选择明智的道路,以免 用声明性语义换取一些有限的加速,就像许多基于元逻辑Prolog谓词的快速修复一样

    幸运的是,我们可以呼救

    compatible([],_). compatible([X|Xs],Ys) :- compatible_(Ys,X,Xs). compatible_([],_,_). compatible_([Y|Ys],X,Xs) :- dif(X,Y), compatible(Xs,Ys).

  • 现在有一个更重要的问题:你只需要处理数字(整数)吗?或者列表的元素可以是其他序言术语吗?你用的是什么序言?(我这样问是因为我无法识别
    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