List 测试列表中的所有列表是否具有相同的长度

List 测试列表中的所有列表是否具有相同的长度,list,prolog,clpfd,prolog-coroutining,meta-predicate,List,Prolog,Clpfd,Prolog Coroutining,Meta Predicate,我试图在Prolog中学习更多关于列表的知识,尤其是列表中的列表。所以我想写一个谓词来确定列表中的列表是否相等。所以如果我这么做了 ?- equalLists([[a,b,c],[1,2,3],[d,4,e],[5,6]]). false 因此,我试图检查每个列表,看看它是否与前一个列表具有相同的长度。有人能给我指出正确的方向吗?首先,我们定义一些标准的高阶关系,map和fold。这需要内置的调用谓词。可以将maxlist等定义为一次性,但这应该更具启发性 其思想是得到一个长度列表,然后比较列

我试图在Prolog中学习更多关于列表的知识,尤其是列表中的列表。所以我想写一个谓词来确定列表中的列表是否相等。所以如果我这么做了

?- equalLists([[a,b,c],[1,2,3],[d,4,e],[5,6]]).
false

因此,我试图检查每个列表,看看它是否与前一个列表具有相同的长度。有人能给我指出正确的方向吗?

首先,我们定义一些标准的高阶关系,
map
fold
。这需要内置的
调用
谓词。可以将
maxlist
等定义为一次性,但这应该更具启发性

其思想是得到一个长度列表,然后比较列表中的最大值是否等于最小值

maplist(_, [], []).
maplist(P, [X | Y], [A | B]) :-
  call(P, X, A),
  maplist(P, Y, B).

max(A, B, M) :- A <  B, M = B.
max(A, B, M) :- A >= B, M = A.

min(A, B, M) :- B <  A, M = B.
min(A, B, M) :- B >= A, M = A.

fold(_, [X], X).
fold(P, [X, Y], R) :- call(P, X, Y, R).
fold(P, [X, Y | Z], R) :-
  fold(P, [Y | Z], NR),
  call(P, NR, X, R).

maxlist(L, M) :- fold(max, L, M).

minlist(L, M) :- fold(min, L, M).

equallists(L) :-
  maplist(length, L, Lengths),
  maxlist(Lengths, Max),
  minlist(Lengths, Min),
  Max == Min.
maplist(u,[],[])。
地图列表(P[X|Y],[A|B]):-
呼叫(P,X,A),
地图列表(P,Y,B)。
最大值(A,B,M):-A=B,M=A。
最小值(A,B,M):-B=A,M=A。
折叠(X,[X],X)。
折叠(P,[X,Y],R):-调用(P,X,Y,R)。
褶皱(P[X,Y | Z],R):-
褶皱(P[Y | Z],NR),
呼叫(P、NR、X、R)。
最大列表(L,M):-折叠(最大,L,M)。
最小列表(L,M):-折叠(最小,L,M)。
平等主义者(L):-
地图列表(长度、L、长度),
最大列表(长度,最大值),
最小列表(长度,最小值),
最大值==最小值。

@Peteris的解决方案过于复杂。您可以这样做:

equal_lengths([]).
equal_lengths([[]]).
equal_lengths([[_|_]]).
equal_lengths([X,Y|Rest]) :- 
  length(X, Len), 
  length(Y, Len), 
  equal_lengths([Y|Rest]).
归纳地思考。我断言空列表的长度和一个列表的长度是“相等的”(没有/只有一个可以比较)。然后我说如果第一个项目的长度等于第二个项目的长度,只要第二个项目的长度和其他项目的长度匹配,我们就可以了

注意:我们并没有明确地说X和Y的长度与某种等式测试相同。我们让Prolog为我们处理这个问题,只需声明X和Y的长度是Len。因此,如果Y的长度与X的长度不一致,谓词将失败

逆转过程

因此,要编写一个谓词来确定列表是否没有相同的长度,我们必须注意,这次我们必须跟踪到目前为止看到的要检查的长度。我们必须将每个列表的长度与前面所有列表的长度进行比较,以确定不平等性。因此,这次我们的初始案例将创建初始长度列表,并将处理延迟到另一个谓词,如:

unequal_lengths(X) :- unequal_lengths(X, []).
现在,我们再次从类似的基本情况开始:

unequal_lengths([], _).
unequal_lengths([[]], _).
unequal_lengths([[_|_]], _).
当我们有一个实际的列表时,事情会变得有趣:

unequal_lengths([X|Rest], Lengths) :-
  length(X, Len),
  \+ member(Len, Lengths),
  unequal_lengths(Rest, [Len|Lengths]).
因此,我们计算这个列表的长度,然后断言这不是我们以前使用handy成员谓词看到的长度,然后将这个长度连同其余部分一起传递给列表的其余部分

附录:不平等与所有

受其他答案的启发,您可以以高阶方式实现不等_长度,如下所示:

unequal_lengths(Lists) :-
  findall(Len, (member(X, Lists), length(X, Len)), Lengths),
  forall(select(Len, Lengths, Remaining), \+ member(Len, Remaining)).

仔细想想,这与问题的形式逻辑表达式非常接近:对于每个列表长度,不存在与此长度对应的剩余列表长度的元素。

我将使用SWI Prolog内置项重写Peteris答案(+1),并:

完成了

更简单的是,使用(此处)调整参数顺序:

:- [lambda].

equallists([H|T]) :-
  length(H, N),
  maplist(\L^length(L, N), T).
南特马Variazione(这应该是最低限度的):

如@false所述,当T不接地时,测试可能失败。可能的更正:

equallists([H|T]) :-
  length(H, N),
  forall(member(L, T), (nonvar(L), length(L, N))).
对于all/2,我认为它可以被描述为故障驱动循环的一种形式,很容易被误用


当然,Prolog中的每个控制流结构都很难正确使用,这可能是该语言很少流行的主要原因。

我发现唯一可以接受的解决方案是chac的最后一个,为了完整性,我添加了空列表处理:

equalLengths([]).
equalLengths([Head|Tail]) :-
    length(Head, Length),
    forall(member(List, Tail), length(List, Length)).
使用正确的工具——和——我们只需要一行:

?- Xss = [[1,2],[2,3],[3,4,5]], maplist(N+\Xs^length(Xs,N),Xss). false. ?- Xss = [[1,2],[2,3],[3,4]], maplist(N+\Xs^length(Xs,N),Xss). N = 2. ?-Xss=[[1,2],[2,3],[3,4,5]],映射列表(N+\Xs^长度(Xs,N),Xss)。 错。 ?-Xss=[[1,2],[2,3],[3,4]],映射列表(N+\Xs^长度(Xs,N),Xss)。 N=2。
(+\)/2
帮助我们声明
N
是免费的,因此我们使用
N
相同的
N
作为
Xss
中每个
的长度
Xss
这是一种解决方案,它利用了大多数Prolog系统中发现的第一个参数索引,以避免在大多数(但不是所有)情况下出现虚假的选择点:

一些示例查询:

| ?- equal_lengths([]). 

yes
| ?- equal_lengths([[]]).

yes
| ?- equal_lengths([_]). 

yes
| ?- equal_lengths([[],_]).

yes
| ?- equal_lengths([_,[]]).

true ? ;

no
| ?- equal_lengths([L1,L2]).

L1 = []
L2 = [] ? ;

L1 = [_]
L2 = [_] ? ;

L1 = [_,_]
L2 = [_,_] ? 

...
| ?- equal_lengths([[a,b,c],[1,2,3],[d,4,e],[5,6]]).

no
| ?- equal_lengths([[a,b,c],[1,2,3],[d,4,e],[5,6,7],L]).

L = [_,_,_]

yes
| ?- equal_lengths([L1,[_,_],L3]).                      

L1 = [_,_]
L3 = [_,_] ? ;

no

| ?- equal_lengths([L1,[_,_|_],L3]).

L1 = [_,_]
L3 = [_,_] ? ;

L1 = [_,_,_]
L3 = [_,_,_] ? ;

L1 = [_,_,_,_]
L3 = [_,_,_,_] ? ;

...
?- Xss = [As,Bs,Cs], As=[], samelength_of(N,Xss). N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = []. ?- Xss = [As,Bs,Cs], samelength_of(N,Xss), As=[]. N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = [].
当第一个元素未绑定且存在绑定列表元素时,我们只会得到一个虚假的选择点(即不会导致解决方案的选择点)。如果没有列表元素绑定到有限的列表,谓词将生成列表长度不断增长的解决方案,如示例查询中所示。

遵循第二个解决方案,与第一次尝试相比具有更好的终止属性。主要思想是在每次遍历列表时,我们从每个列表中删除一个元素

equal_lengths([]).
equal_lengths([L1| Ls]) :-
    pick(L1, Ls, Rs),
    equal_lengths(Rs).

pick([], Ls, []) :-
    all_empty(Ls).
pick([_| R1], Ls, [R1| Rs]) :-
    pick(Ls, Rs).

pick([], []).
pick([[_|R1]| Ls], Rs) :-
    pick([_|R1], Ls, Rs).

all_empty([]).
all_empty([[]| Rs]) :-
    all_empty(Rs).
在对我的第一个解决方案的评论中提到的问题案例@false是:

| ?- equal_lengths([_,_,[]]).

true ? ;

no
但是,更清楚的是,如果不使用匿名变量,我们可以得到唯一正确的解决方案:

| ?- equal_lengths([L1,L2,[]]).

L1 = []
L2 = [] ? ;

no
在我的第一个解决方案中,前面的所有示例查询都没有问题。有一个查询特别值得一提,因为它错误地只提供了一个解决方案,而没有在以前的尝试中生成解决方案。现在它如预期的那样工作:

| ?- equal_lengths([L]).

L = [] ? ;

L = [_] ? ;

L = [_,_] ? ;

L = [_,_,_] ? ;

...

有人能找到导致此解决方案出现问题的示例查询吗?

我菜单上的下一道菜:大杂烩

:- use_module(library(clpfd)).

samelength_of(N,Xss) :- maplist(length_of__lazy(N),Xss).

length_of__lazy(N,Xs) :-
   N #>= 0,
   (  nonvar(N)
   -> length(Xs,N)
   ;  var(Xs)
   -> when((nonvar(Xs);nonvar(N)), length_of__lazy(N,Xs))
   ;  Xs = []
   -> N = 0
   ;  Xs = [_|Xs0]
   -> N0 + 1 #= N,
      length_of__lazy(N0,Xs0)
   ;  throw(error(type_error(list,Xs),length_of__lazy/2))
   ).

my_indomain(N) :-
   fd_inf(N,I),
   (  N #= I
   ;  N #> I, my_indomain(N)
   ).
一些示例查询:

| ?- equal_lengths([]). 

yes
| ?- equal_lengths([[]]).

yes
| ?- equal_lengths([_]). 

yes
| ?- equal_lengths([[],_]).

yes
| ?- equal_lengths([_,[]]).

true ? ;

no
| ?- equal_lengths([L1,L2]).

L1 = []
L2 = [] ? ;

L1 = [_]
L2 = [_] ? ;

L1 = [_,_]
L2 = [_,_] ? 

...
| ?- equal_lengths([[a,b,c],[1,2,3],[d,4,e],[5,6]]).

no
| ?- equal_lengths([[a,b,c],[1,2,3],[d,4,e],[5,6,7],L]).

L = [_,_,_]

yes
| ?- equal_lengths([L1,[_,_],L3]).                      

L1 = [_,_]
L3 = [_,_] ? ;

no

| ?- equal_lengths([L1,[_,_|_],L3]).

L1 = [_,_]
L3 = [_,_] ? ;

L1 = [_,_,_]
L3 = [_,_,_] ? ;

L1 = [_,_,_,_]
L3 = [_,_,_,_] ? ;

...
?- Xss = [As,Bs,Cs], As=[], samelength_of(N,Xss). N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = []. ?- Xss = [As,Bs,Cs], samelength_of(N,Xss), As=[]. N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = []. 比目鱼不是你的口味吗?没问题


你的第二种情况应该是
等长([[[]]])。
-你不希望任何非列表列表成功。刚刚意识到我们需要另一种基本情况,
等长([]])。
我有另一个简单的问题,我该如何扭转这种情况。就像我想确保所有列表都不相等一样。@NickBarnes在这种情况下可能不是 ?- Xss = [As,Bs,Cs], As=[], samelength_of(N,Xss). N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = []. ?- Xss = [As,Bs,Cs], samelength_of(N,Xss), As=[]. N = 0, Xss = [[],[],[]], As = [], Bs = [], Cs = [].
?- samelength_of(N,[As,Bs,Cs]).
N in 0..sup,
when((nonvar(As);nonvar(N)), length_of__lazy(N,As)),
when((nonvar(Bs);nonvar(N)), length_of__lazy(N,Bs)),
when((nonvar(Cs);nonvar(N)), length_of__lazy(N,Cs)).
?- samelength_of(N,[As,Bs,Cs]), my_indomain(N).
N = 0, As = [],            Bs = [],            Cs = []            ;
N = 1, As = [_A1],         Bs = [_B1],         Cs = [_C1]         ;
N = 2, As = [_A1,_A2],     Bs = [_B1,_B2],     Cs = [_C1,_C2]     ;
N = 3, As = [_A1,_A2,_A3], Bs = [_B1,_B2,_B3], Cs = [_C1,_C2,_C3] ...