这是受到我曾经实现的功能性高阶习语工具箱的启发。那时我发现角落案例令人痛苦,我今天仍然这样做:)另外,找到好名字总是一个问题......
考虑元谓词mapadj/4
:
mapadj(Relation_4,As,Bs,Cs) :-
list_list_list_mapadj(As,Bs,Cs,Relation_4).
list_list_list_mapadj([],[],[],_).
list_list_list_mapadj([A|As],Bs,Cs,Relation_4) :-
list_prev_list_list_mapadj(As,A,Bs,Cs,Relation_4).
list_prev_list_list_mapadj([],_,[],[],_).
list_prev_list_list_mapadj([A1|As],A0,[B|Bs],[C|Cs],Relation_4) :-
call(Relation_4,A0,A1,B,C),
list_prev_list_list_mapadj(As,A1,Bs,Cs,Relation_4).
样品用途:
z_z_sum_product(X,Y,Sum,Product) :-
Sum #= X + Y,
Product #= X * Y.
:- mapadj(z_z_sum_product,[], [], []).
:- mapadj(z_z_sum_product,[1], [], []).
:- mapadj(z_z_sum_product,[1,2], [3], [2]).
:- mapadj(z_z_sum_product,[1,2,3], [3,5], [2,6]).
:- mapadj(z_z_sum_product,[1,2,3,4],[3,5,7],[2,6,12]).
我知道角落案例中的裂痕As = []
,As = [_]
但我仍然觉得这与“所有相邻列表项”一样接近。
此外,所有这些都可以轻松扩展:
- 下降到
mapadj/2
(类似于chain/2
,除了单例列表的类型检查)
- 侧身,带有额外的状态参数,到
foldadjl/n
,scanadjl/n
关于名称:IMO l
/r
后缀是必需的fold
/ scan
,但不是map
.
编辑 2015-04-26
这是前面提到的foldadjl/4
:
foldadjl(Relation_4,Xs) -->
list_foldadjl(Xs,Relation_4).
list_foldadjl([],_) -->
[].
list_foldadjl([X|Xs],Relation_4) -->
list_prev_foldadjl(Xs,X,Relation_4).
list_prev_foldadjl([],_,_) -->
[].
list_prev_foldadjl([X1|Xs],X0,Relation_4) -->
call(Relation_4,X0,X1),
list_prev_foldadjl(Xs,X1,Relation_4).
编辑 2015-04-27
这里是 meta-predicate splitlistIfAdj/3
,基于
if_/3
它是在先前关于具体化的答案中提出的
。
split_if_adj(P_3,As,Bss) :- splitlistIfAdj(P_3,As,Bss).
splitlistIfAdj(P_3,As,Bss) :-
list_split_(As,Bss,P_3).
list_split_([],[],_).
list_split_([X0|Xs], [Cs|Bss],P_3) :-
list_prev_split_(Xs,X0,Cs,Bss, P_3).
list_prev_split_([], X, [X],[],_).
list_prev_split_([X1|Xs],X0,[X0|Cs],Bss,P_3) :-
if_(call(P_3,X0,X1),
(Cs = [], Bss = [Cs0|Bss0]),
(Cs = Cs0, Bss = Bss0)),
list_prev_split_(Xs,X1,Cs0,Bss0,P_3).
为了在使用中显示它,让我们定义与翻转真值dif/3
完全相同的方式:(=)/3
dif(X, Y, R) :- X == Y, !, R = false.
dif(X, Y, R) :- ?=(X, Y), !, R = true. % syntactically different
dif(X, Y, R) :- X \= Y, !, R = true. % semantically different
dif(X, Y, R) :- R == false, !, X = Y.
dif(X, X, false).
dif(X, Y, true) :-
dif(X, Y).
现在我们一起使用它们:
?- splitlistIfAdj(dif,[1,2,2,3,3,3,4,4,4,4],Pss).
Pss = [[1],[2,2],[3,3,3],[4,4,4,4]]. % succeeds deterministically
如果我们概括一些列表项怎么办?我们是否得到了具有正确未决目标的多个答案?
首先,一个小例子:
?- splitlistIfAdj(dif,[1,X,2],Pss).
X = 1, Pss = [[1,1],[2]] ;
X = 2, Pss = [[1],[2,2]] ;
dif(X,1),dif(X,2), Pss = [[1],[X],[2]].
一个更大的例子,涉及两个变量X
和Y
。
?- splitlistIfAdj(dif,[1,2,2,X,3,3,Y,4,4,4],Pss).
X = 2, Y = 3, Pss = [[1],[2,2,2],[3,3,3],[4,4,4]] ;
X = 2, Y = 4, Pss = [[1],[2,2,2],[3,3],[4,4,4,4]] ;
X = 2, dif(Y,3),dif(Y,4), Pss = [[1],[2,2,2],[3,3],[Y],[4,4,4]] ;
X = Y, Y = 3, Pss = [[1],[2,2],[3,3,3,3],[4,4,4]] ;
X = 3, Y = 4, Pss = [[1],[2,2],[3,3,3],[4,4,4,4]] ;
X = 3, dif(Y,3),dif(Y,4), Pss = [[1],[2,2],[3,3,3],[Y],[4,4,4]] ;
dif(X,2),dif(X,3), Y = 3, Pss = [[1],[2,2],[X],[3,3,3],[4,4,4]] ;
dif(X,2),dif(X,3), Y = 4, Pss = [[1],[2,2],[X],[3,3],[4,4,4,4]] ;
dif(X,2),dif(X,3), dif(Y,3),dif(Y,4), Pss = [[1],[2,2],[X],[3,3],[Y],[4,4,4]].
编辑 2015-05-05
这是tpartition/4
:
tpartition(P_2,List,Ts,Fs) :- tpartition_ts_fs_(List,Ts,Fs,P_2).
tpartition_ts_fs_([],[],[],_).
tpartition_ts_fs_([X|Xs0],Ts,Fs,P_2) :-
if_(call(P_2,X), (Ts = [X|Ts0], Fs = Fs0),
(Ts = Ts0, Fs = [X|Fs0])),
tpartition_ts_fs_(Xs0,Ts0,Fs0,P_2).
样品用途:
?- tpartition(=(0), [1,2,3,4,0,1,2,3,0,0,1], Ts, Fs).
Ts = [0, 0, 0],
Fs = [1, 2, 3, 4, 1, 2, 3, 1].
编辑 2015-05-15
不断地,......这里是splitlistIf/3
:
split_if(P_2,As,Bss) :- splitlistIf(P_2,As,Bss).
splitlistIf(P_2,As,Bss) :-
list_pred_split(As,P_2,Bss).
list_pred_split([],_,[]).
list_pred_split([X|Xs],P_2,Bss) :-
if_(call(P_2,X), list_pred_split(Xs,P_2,Bss),
(Bss = [[X|Ys]|Bss0], list_pred_open_split(Xs,P_2,Ys,Bss0))).
list_pred_open_split([],_,[],[]).
list_pred_open_split([X|Xs],P_2,Ys,Bss) :-
if_(call(P_2,X), (Ys = [], list_pred_split(Xs,P_2,Bss)),
(Ys = [X|Ys0], list_pred_open_split(Xs,P_2,Ys0,Bss))).
让我们使用它:
?- splitlistIf(=(x),[x,1,2,x,1,2,3,x,1,4,x,x,x,x,1,x,2,x,x,1],Xs).
Xs = [[1, 2], [1, 2, 3], [1, 4], [1], [2], [1]].