我正在尝试更多地了解Prolog中的列表,尤其是列表中的列表。所以我想编写一个谓词来确定列表中的列表是否相等。所以,如果我这样做了
?- equalLists([[a,b,c],[1,2,3],[d,4,e],[5,6]]).
false
所以我试图检查每个列表,看它是否与前一个列表的长度相同。有人能指出我正确的方向吗?
答案 0 :(得分:4)
首先,我们定义一些标准的高阶关系,map
和fold
。这需要内置的call
谓词。可以将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.
答案 1 :(得分:3)
@ 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]).
所以我们计算这个列表的长度,然后断言这不是我们之前看到的方便成员谓词的长度,然后将这个长度和其余长度一起传递给列表的其余部分。
附录:不平等w / forall
受其他答案的启发,您可以按照更高阶的方式实现unequal_lengths:
unequal_lengths(Lists) :-
findall(Len, (member(X, Lists), length(X, Len)), Lengths),
forall(select(Len, Lengths, Remaining), \+ member(Len, Remaining)).
如果你考虑一下,这与问题的形式逻辑表达非常接近:对于每个列表长度,不存在与此对应的剩余列表长度的元素。
答案 2 :(得分:2)
我将使用SWI-Prolog builtins maplist和aggregate重写Peteris的答案(+1):
equallists(L) :-
maplist(length, L, Lengths),
aggregate(max(T), member(T, Lengths), N),
aggregate(min(T), member(T, Lengths), N).
完成!
更简单,使用lambda(此处为doc page)调整参数顺序:
:- [lambda].
equallists([H|T]) :-
length(H, N),
maplist(\L^length(L, N), T).
Variazione sul tema(这应该是最小的):
equallists([H|T]) :-
length(H, N),
forall(member(L, T), length(L, N)).
如@false所述,当T未接地时,测试可能会失败。可能的纠正:
equallists([H|T]) :-
length(H, N),
forall(member(L, T), (nonvar(L), length(L, N))).
forall / 2,我认为可以被描述为失败驱动循环的一种形式,很容易被误用。
OTOH,Prolog中的每个控制流构造都很难正确使用,这可能是该语言缺乏流行的主要原因。答案 3 :(得分:2)
利用大多数Prolog系统中发现的第一个参数索引的解决方案,以避免在大多数(但不是全部)情况下出现假选择点:
E:\work\workspace\knowlege\play-scala-di>sbt
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=256m; support was removed in 8.0
java.lang.IllegalArgumentException: URI has an authority component
at java.io.File.<init>(File.java:423)
at sbt.Classpaths$.sbt$Classpaths$$bootRepository(Defaults.scala:1758)
at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1729)
at sbt.Classpaths$$anonfun$appRepositories$1.apply(Defaults.scala:1729)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:34)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at sbt.Classpaths$.appRepositories(Defaults.scala:1729)
at sbt.Classpaths$$anonfun$41.apply(Defaults.scala:1102)
at sbt.Classpaths$$anonfun$41.apply(Defaults.scala:1102)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
at sbt.EvaluateSettings$MixedNode.evaluate0(INode.scala:175)
at sbt.EvaluateSettings$INode.evaluate(INode.scala:135)
at sbt.EvaluateSettings$$anonfun$sbt$EvaluateSettings$$submitEvaluate$1.apply$mcV$sp(INode.scala:69)
at sbt.EvaluateSettings.sbt$EvaluateSettings$$run0(INode.scala:78)
at sbt.EvaluateSettings$$anon$3.run(INode.scala:74)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
[error] java.lang.IllegalArgumentException: URI has an authority component
一些示例查询:
equal_lengths([]).
equal_lengths([L1| Ls]) :-
equal_lengths_aux(Ls, L1).
equal_lengths_aux([], _).
equal_lengths_aux([L2| Ls], L1) :-
equal_length(L1, L2),
equal_lengths_aux(Ls, L2).
equal_length([], []).
equal_length([_| Tail1], [_| Tail2]) :-
equal_length(Tail1, Tail2).
当第一个元素未绑定且存在绑定列表元素时,我们只会得到虚假选择点(即不会导致解决方案的选择点)。如果没有列表元素绑定到有限列表,谓词将生成列表长度不断增长的解决方案,如示例查询中所示。
答案 4 :(得分:2)
与第一次尝试相比,遵循第二种具有更好终止属性的解决方案。主要思想是每次遍历列表时,我们从每个列表中删除一个元素。
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 = [_,_,_] ? ;
...
任何人都可以找到导致此解决方案出现问题的示例查询吗?
答案 5 :(得分:2)
菜单上的下一道菜:baroque clpfd prolog-coroutining大杂烩。
$updatequality = $database->prepare("UPDATE products SET quantity=quantity - 1 AND purchases=purchases + 1 WHERE id=?");
一些示例查询:
?- 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 = [].
更多?想试试比目鱼吗?
:- 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)
).
比目鱼不是你的口味吗? 没问题!
?- 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)).
答案 6 :(得分:1)
使用正确的工具--- meta-predicate maplist/2
和Prolog lambdas ---我们只需要一行:
?- 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.
(+\)/2
帮助我们声明N
是免费的,因此我们使用相同的N
作为Xs
Xss
的长度while (my_fgets(buf, sizeof(buf), f))
printf("%s\n", buf);
1}}。
答案 7 :(得分:-2)
我发现唯一可接受的解决方案是chac的最后一个,为了完整性我会添加空列表处理:
equalLengths([]).
equalLengths([Head|Tail]) :-
length(Head, Length),
forall(member(List, Tail), length(List, Length)).