2016-11-24 43 views
3

我有一個列表L給出和我的任務是創建累積重複,這取決於我想要多少。Prolog - 在列表中創建累積重複項?

我有例如列表[a,b,c,d],想的第一個元素是重複4次(可選),然後每個後續元件必須被複制像前一個+ 1

假設我的謂詞被稱爲list_copy(L,N,R),與L = [a,b,c,d]K = 2的結果應該是:

?- list_copy([a,b,c,d],2,R). 
R = [a,a,b,b,b,c,c,c,c,d,d,d,d,d] 

我已經成功地進行復制列表兩次創建一個通用的代碼:

dupl([],[]). 
dupl([O|U],[O,O|U1]) :- dupl(U,U1). 

根據我放入第二行的O有多少我得到那麼多重複。

我的問題是,但是:我如何實現第三個變量作爲累計計數器,以獲得預期的結果?

+0

儘管我想給你的答案:考慮添加一個謂詞n_of(N,Element,List),它會給你一個N次元素列表,如下所示: '? - n_of(2,a,L )' 'L = [a,a]' –

+0

@SpinyNorman對於差異列表,如果'n_of'有4個參數而不是3個,那將會更好。否則,'n_of/3'就像'length(L,N),maplist(=(Element),L)'一樣簡單。 – 2016-11-25 02:40:40

回答

3

當你必須一個一個「計數」的東西,考慮使用succ/2。它具有很好的屬性,它可以同時工作,並且在與succ(X, 0)通話時失敗。

因此,首先,做「累積重複」謂詞:

cum_dup([], _, []). 
cum_dup([X|Xs], N, Ys) :- 
    repeat_n(X, N, Ys, Back), 
    succ(N, N1), 
    cum_dup(Xs, N1, Back). 

這使用謂詞repeat_n/4,這需要一個元件,一個非負整數,並且重複的元素。它在列表的後面留下一個「洞」,您可以使用cum_dup/3填充結果的其餘部分。這裏是一個直觀的實現的repeat_n/4

repeat_n(_, 0, L, L). 
repeat_n(X, N, [X|Xs], Rest) :- 
    succ(N0, N), 
    repeat_n(X, N0, Xs, Rest). 

這已經給你所需要的結果:

?- cum_dup([a,b,c,d], 2, R). 
R = [a, a, b, b, b, c, c, c, c, d, d, d, d, d] ; 
false 

它留下一個無害的選擇點之後。有太多的方法可以讓repeat_n/4不留下不必要的選用要點:

  • 使用CLP(FD)
  • 使用切割
  • 使用條件(IF-THEN-ELSE)
  • 使用的結構,而不是一個整數的

只是一個例子:

repeat_n(X, N, L, Back) :- 
    length(Ns, N), 
    repeat_n_(Ns, X, L, Back). 

repeat_n_([], _, L, L). 
repeat_n_([_|Ns], X, [X|Xs], L) :- 
    repeat_n_(Ns, X, Xs, L). 

這裏,您不用一個整數來計算,而是(ab)使用該長度的列表。

我想你可以自己想一想,如果你真的需要問另一個問題。

1

---編輯---修改使用succ/2,如鮑里斯建議(謝謝!)。

我想你可以使用輔助子句。像在下面的例子中

list_copy_h([], _, _, []). 

list_copy_h([_ | Tin], 0, Num, Lout) :- 
    succ(Num, Np1), 
    list_copy_h(Tin, Np1, Np1, Lout). 

list_copy_h([H | Tin], Count, Num, [H | Tout]) :- 
    succ(Cm1, Count), 
    list_copy_h([H | Tin], Cm1, Num, Tout). 

list_copy(Lin, Num, Lout) :- 
    list_copy_h(Lin, Num, Num, Lout). 

list_copy_h/4的想法是使用減小到零的計數器(第二個參數)。當爲零時,輸入列表的頭部放電,循環再次以輸入列表的下列元素開始,但增加計數器的起始值。第三個參數是起始值。

+0

你可以用'succ(N0,N)'來代替'N> 0,N0是N-1'。 – 2016-11-25 02:44:57

+0

@Boris - 非常有用;謝謝!我不知道'succ/2'只適用於非負整數。不幸的是我的gprolog(舊版本)不支持它。 – max66

+0

@ maq66:在GNU Prolog中,您可以使用CLP(FD)約束輕鬆編程'succ/2'! – mat