TL;DR:要将E
位置处的项目I1
插入列表Es0
,我们不需要编写递归代码。
相反,我们可以将工作(以及对正确处理的担忧!)委托给通用的辅助谓词,所有这些都是Prolog 序言的一部分。为了定义ins_/4
我们写:
ins_(E, Es0, I1, Es) :-
maplist (any_thing, Es, [_|Es0]),
append (Prefix, Suffix, Es0),
length ([_|Prefix], I1),
append (Prefix, [ E|后缀], Es)。
任何事物(_, _)。% 辅助谓词(上面使用过)
注意maplist(any_thing, Es, [_|Es0])
相当于same_length(Es, [_|Es0])
。
使用 GNU Prolog 版本 1.4.4(64 位)的示例查询1、2、3 :
?- ins_(X, [a,b,c,d,e], N1, Xs)。
N1 = 1, Xs = [ X ,a,b,c,d,e]
; N1 = 2, Xs = [a, X ,b,c,d,e]
; N1 = 3, Xs = [a,b, X ,c,d,e]
; N1 = 4, Xs = [a,b,c, X ,d,e]
; N1 = 5, Xs = [a,b,c,d, X ,e]
; N1 = 6, Xs = [a,b,c,d,e, X ]
; 错误的。
?- ins_(X, [a,b,c,d,e], 3, Xs)。
Xs = [a,b, X ,c,d,e]
; 错误的。
?- ins_(X, Xs0, 3, [a,b, c ,d,e])。
X = c, Xs0 = [a,b,d,e]
; 错误的。
让我们不要忘记最一般的查询!
?- ins(X, Es0, I1, Es)。
Es0 = [],I1 = 1,Es = [ X ]
;
Es0 = [A], I1 = 1, Es = [ X ,A]
; Es0 = [A], I1 = 2, Es = [A, X ]
;
Es0 = [A,B], I1 = 1, Es = [ X ,A,B]
; Es0 = [A,B], I1 = 2, Es = [A, X ,B]
; Es0 = [A,B], I1 = 3, Es = [A,B, X ]
;
Es0 = [A,B,C], I1 = 1, Es = [ X ,A,B,C]
; Es0 = [A,B,C], I1 = 2, Es = [A, X ,B,C]
; Es0 = [A,B,C], I1 = 3, Es = [A,B, X ,C]
; Es0 = [A,B,C], I1 = 4, Es = [A,B,C, X ]
;
Es0 = [A,B,C,D], I1 = 1, Es = [ X ,A,B,C,D]
; ...
公平枚举所有解决方案,OK!
编辑:我重复了@m09 在他对 SWI-Prolog 7.3.11 和 SICStus Prolog 4.3.2的回答ins3/4
中定义
的最一般的查询(两者都具有 library predicate )。我很惊讶地看到展示不同程序语义的底层实现(wrt“公平枚举”)。你自己看!nth1/4
nth1/4
% SICStus Prolog 4.3.2 % SWI Prolog 7.3.11
% %
?- ins3( X , Es0, I1, Es)。% ?- ins3( X , Es0, I1, Es)。
I1 = 1, Es0 = [], Es = [ X ] % I1 = 1, Es = [ X |Es0]
; % ; I1 = 2, Es0 = [_A|_Z],
I1 = 1, Es0 = [_A], Es = [ X ,_A] % Es = [_A, X |_Z]
; I1 = 2, Es0 = [_A], Es = [_A, X ] % ; I1 = 3, Es0 = [_A,_B|_Z],
; % Es = [_A,_B, X |_Z]
I1 = 1, Es0 = [_A,_B], Es = [ X ,_A,_B] % ; I1 = 4, Es0 = [_A,_B,_C|_Z],
; I1 = 2, Es0 = [_A,_B], Es = [_A, X ,_B] % Es = [_A,_B,_C, X |_Z],
; I1 = 3, Es0 = [_A,_B], Es = [_A,_B, X ] % ; I1 = 5, Es0 = [_A,_B,_C,_D|_Z],
; % Es = [_A,_B,_C,_D, X |_Z]
... % ...
脚注 1:上面显示的所有示例查询都会普遍终止。
脚注 2: GNU Prolog toplevel 给出的答案已经打印了一些。
脚注 3:上述代码按原样使用,不需要额外的库谓词。