4

我正在尝试在 Prolog 中编写一个程序,它将一个元素插入到某个位置,例如

?- ins(a, [1,2,3,4,5], 3, X).
X = [1,2,a,3,4,5].

我有以下代码:

ins(X,[H|T],P,OUT) :-
   length([T3],P),
   concatenate(X,[H],T),
   ins(...). 

问题是它X从后面插入给定索引中的元素(我什至知道问题出在哪里->length([T3],P)这显然是列表的长度从后面而不是从头开始)。X我试图记住当“截断元素的数量”= 时我截断并插入了多少元素P,但我无法在 Prolog 中真正写出来。有任何想法吗?

4

4 回答 4

3
% ins(Val,List,Pos,Res)

ins(Val,[H|List],Pos,[H|Res]):- Pos > 1, !, 
                                Pos1 is Pos - 1, ins(Val,List,Pos1,Res). 
ins(Val, List, 1, [Val|List]).

如果 Pos = 0 或 Pos > length(List) + 1,则谓词失败

于 2012-04-08T15:03:13.283 回答
3

让我们在这里说明你想要什么。例如,您可以说:“我想在元素List之后拆分我的输入,Position - 1以便我可以在那里插入一个新元素”。

直接翻译append/3(DCG会更好):

ins(Element, List, Position, Result) :-
    PrefixLength is Position - 1,
    length(Prefix, PrefixLength),
    append(Prefix, Suffix, List),
    append(Prefix, [Element], Temp),
    append(Temp, Suffix, Result).

或者你可以说:“我想在不接触任何东西的情况下经历我那个List Position - 1时代的元素,然后插入Element,然后再不接触任何东西”。

这一次的直接翻译是:

ins2(Element, List, 1, [Element|List]).
ins2(Element, [Head|Tail], Position, [Head|Result]) :-
    Position > 1,
    NewPosition is Position - 1,
    ins2(Element, Tail, NewPosition, Result).

你也可以这样说:“我的输入List是一个等于我的列表,Result除了它没有我ElementPosition元素。” 并意识到如果你使用 swi-prolog,谓词会立即解决这个问题:

ins3(Element, List, Position, Result) :-
    nth1(Position, Result, Element, List).

底线是:清楚地说明问题是什么,解决方案应该简单明了。

于 2012-04-08T15:13:48.250 回答
2

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/4nth1/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:上述代码按原样使用,不需要额外的库谓词。

于 2015-11-30T22:15:39.913 回答
0
ins(Element,List,Nth,Result) :-
    length([_|L0],Nth),
    append(L0,[_|R],List),
    append(L0,[Element|R],Result).
于 2012-04-17T07:21:35.870 回答