我们可以解决您的问题并保持逻辑纯度!
在下面的 let Xs
be 中[1,1,1,2,2,2,3,1,1]
,您在问题中使用的列表。
首先,我们映射Xs
到一个列表列表,Yss
这样每个列表Ys
中的每个列表Yss
都只包含来自 的相等元素Xs
。我们通过将元谓词splitlistIfAdj/3
与具体化的不等式谓词结合使用来做到这一点dif/3
:
?- Xs = [1,1,1,2,2,2,3,1,1], splitlistIfAdj(dif,Xs,Yss).
Xs = [ 1,1,1, 2,2,2, 3, 1,1 ],
Yss = [[1,1,1],[2,2,2],[3],[1,1]].
其次,我们将列表列表映射Yss
到Zss
. 中的每一项 Zss
都有形式[Element,Amount]
。查看上述查询的答案,我们看到我们需要做的就是映射到、到、到和到。正是这样做的:[1,1,1]
[1,3]
[2,2,2]
[2,3]
[3]
[3,1]
[1,1]
[1,2]
run_pair/2
run_pair(Ys,[Element,Amount]) :-
Ys = [Element|_],
length(Ys,Amount).
让我们在 meta-predicate 的帮助下run_pair/2
映射 的每个项目:Yss
maplist/3
?- Yss = [[1,1,1],[2,2,2],[3],[1,1]], maplist(run_pair,Yss,Zss)。
Yss = [[ 1 , 1 , 1 ],[ 2 , 2 , 2 ],[ 3 ] ,[ 1 , 1 ]],
Zss = [[ 1 , 3 ], [ 2 , 3 ], [ 3 , 1 ],[ 1 , 2 ]]。
完毕!是时候把它们放在一起了:
count(Xs,Zss) :-
splitlistIfAdj(dif,Xs,Yss),
maplist(run_pair,Yss,Zss).
让我们看看上面的查询是否仍然有效:)
?- count([1,1,1,2,2,2,3,1,1],Zss).
Zss = [[1,3],[2,3],[3,1],[1,2]]. % succeeds deterministically
由于实现count/2
是单调的,即使在使用非基本术语时,我们也会得到逻辑上合理的答案。让我们看看实际情况!
?- Xs = [A,B,C,D], count(Xs,Zss).
Xs = [D,D,D,D], A=B, B=C , C=D , Zss = [ [D,4]] ;
Xs = [C,C,C,D], A=B, B=C , dif(C,D), Zss = [ [C,3],[D,1]] ;
Xs = [B,B,D,D], A=B, dif(B,C), C=D , Zss = [ [B,2], [D,2]] ;
Xs = [B,B,C,D], A=B, dif(B,C), dif(C,D), Zss = [ [B,2],[C,1],[D,1]] ;
Xs = [A,D,D,D], dif(A,B), B=C , C=D , Zss = [[A,1], [D,3]] ;
Xs = [A,C,C,D], dif(A,B), B=C , dif(C,D), Zss = [[A,1], [C,2],[D,1]] ;
Xs = [A,B,D,D], dif(A,B), dif(B,C), C=D , Zss = [[A,1],[B,1], [D,2]] ;
Xs = [A,B,C,D], dif(A,B), dif(B,C), dif(C,D), Zss = [[A,1],[B,1],[C,1],[D,1]].