2012-04-08 64 views
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)这显然是从后面列表的长度不是从头开始)。我试图记住我切断了多少元素,并在“截断元素数量”= P时插入X,但我无法真正在Prolog中编写它。有任何想法吗?

回答

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>长度(列表),你想要的这里+ 1

2

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

直接TRADUCTION与append/3(DCG会更好BTW):

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

或者你可以说:“我想通过我的ListPosition - 1倍的元素,而无需接触任何东西,然后插入Element和那么不要再碰任何东西“。

这一次直接TRADUCTION是:

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-序言,谓词解决了这个瞬间:

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

底线是:陈述问题是什么清晰的解决方案应该出现在简单的术语。

+0

pos> 1,newPos是P-1,wuaa这就是我一直在寻找的东西:) thx很多 – Johnzzz 2012-04-08 15:29:04

0
ins(Element,List,Nth,Result) :- 
    length([_|L0],Nth), 
    append(L0,[_|R],List), 
    append(L0,[Element|R],Result). 
+1

虽然这段代码可能会回答这个问题,但最好解释它如何解决问题以及为什么要使用它。从长远来看,仅有代码的答案是没有用的。 – 2015-11-30 20:37:15

+0

查询' - ?ins_(A,[1,2,3,4,5],3,[1,2,A,3,4,5])'失败,它应该成功。 OTOH查询' - ?ins_(A,[1,2,3,4,5],3,[1,2,A,4,5])'成功,则它应该失败。要修复这个bug,你需要删除正好4个字符:) – repeat 2015-12-01 01:11:35

2

TL; DR:要在I1位置插入项目E到列表Es0,我们不需要编写递归代码。相反,我们可以将工作(以及对获取它的担忧也归功于!)转换为多功能辅助谓词,所有这些都是Prolog prologue的一部分。要定义ins_/4我们写:

 
ins_(E, Es0, I1, Es) :- 
    maplist (any_thing, Es, [_|Es0]), 
    append (Prefix, Suffix, Es0), 
    length ([_|Prefix], I1), 
    append (Prefix, [E|Suffix], Es). 

any_thing(_, _).      % auxiliary predicate (used above) 

注意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] 
; false. 

?- ins_(X, [a,b,c,d,e], 3, Xs). 
    Xs = [a,b,X,c,d,e] 
; false. 

?- ins_(X, Xs0, 3, [a,b,c,d,e]).    
    X = c, Xs0 = [a,b,d,e] 
; false. 

让我们不要忘记最普通的查询!

 
?- 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] 
; ... 

所有解决方案的公平列举,好的!

编辑: 我重复最常用的查询与ins3/4作为SWI-Prolog的7.3.11和SICStus Prolog的4.3.2(都采用库谓词nth1/4)定义 by @m09 in his answer。 我很惊讶地看到的nth1/4的底层实现表现出不同的程序语义(w.r.t.“公平枚举”)。你自己看!

 
% 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顶层给出的答案已经相当印刷了一点。
脚注3:以上代码用于原样,不需要额外的库谓词。