2016-11-29 157 views
0

我創建一個謂語enum,需要一個列表,例如[1,2,3,4]3一個數字,返回包含做出來的引進名單的長度3的名單列表。所以在給出的例子中enum([1,2,3,4],3,[[1,2,3],[2,3,4]])。 我創建了一個只需要第一個長度爲N的列表的函數,但是當我嘗試循環以獲取所有其他列表時,出現錯誤。感謝您的幫助。序言:遍歷一個列表,並創建一個謂語

append([],L,L). 
append([H|T],L2,[H|L3]):- append(T,L2,L3). 

len([],0). 
len([_|B],X):- len(B,X1), X is X1+1. 

take(_,X,Y) :- X =< 0, !, X =:= 0, Y = []. 
take([],_,[]). 
take([A|B],X,[A|C]):- Z is X-1, take(B,Z,C). 

enum([],_,[]). 
enum([N1|N2],N3,N4):- 
    len([N1|N2],U), 
    N3=<U, 
    take([N1|N2],N3,T1), 
    append([N4],[T1],T2), 
    !, 
    enum(N2,N3,T2). 

回答

0

我將重點放在take/3斷言,這是你的問題的核心。爲了獲得像這樣的子列表,您必須能夠跳過第一個元素,並且只需要其他子列表。

take([_|Xs], N, Ys) :- take(Xs, N, Ys). 

有了這個,你現在得到長度爲3的幾個不同的子列表,但也有一些其他多餘的解決方案:

?- take([1,2,3,4], 3, Xs). 
Xs = [1, 2, 3] ; 
Xs = [1, 2, 4] ; 
Xs = [1, 2] ; 
Xs = [1, 3, 4] ; 
Xs = [1, 3] ; 
Xs = [1, 4] ; 
Xs = [1] % etc. 

您可以通過增加此條款,以您的定義實現這一目標是因爲您的子句take([], _, [])接受空列表作爲空列表的「任意長度的子列表」。我覺得你只是想接受空單的長度爲0的子列表如果刪除此條款,您的第一條將強制執行,而你只能得到確切長度3的解決方案:

?- take([1,2,3,4], 3, Xs). 
Xs = [1, 2, 3] ; 
Xs = [1, 2, 4] ; 
Xs = [1, 3, 4] ; 
Xs = [2, 3, 4] ; 
false. 

作爲一個邊注意,你的第一句話是罰款,是的,但它可以簡化位:

take(_,X,Y) :- X = 0, !, Y = []. 

我也建議你使用更加易讀的變量名。對於列表長度等數字,我們經常使用N。對於列表,通常使用名稱,如Xs,Ys等,其中X,Y等用於相應列表的成員。

最後,要找到謂詞的所有解決方案,需要使用系統謂詞,如setof,bagoffindall。沒有辦法在純Prolog中編寫您的enum

+1

我感覺這是關於滑動窗口,而不是關於給定長度的所有子序列。這僅僅是通過閱讀這個例子,我不認爲這是在問題中明確定義的。 – 2016-11-29 12:50:31

0

因爲我不確定其他答案中的建議,下面是我對你的問題的看法。

首先,不要定義自己的append/3length/2append/3是現在Prolog的民間傳說,你可以在textbooks 30 years old找到它。並且length/2真的很難獨立完成,請使用內置的。

現在:採取在列表L的前第一N元素,你可以說:

length(Front, N), 
append(Front, _, L) 

你創建你所需要的長度的列表,然後使用append/3拆斷這個前從你有的名單。

考慮到這一點,就足以界定謂詞sliding_window/3

sliding_window(L, N, [L]) :- 
     length(L, N). 
sliding_window(L, N, [W|Ws]) :- 
     W = [_|_], % W should be at least one long 
     length(W, N), 
     append(W, _, L), 
     L = [_|L0], 
     sliding_window(L0, N, Ws). 

這類作品,但它會爲您提供所有有用的答案後循環:

?- sliding_window([a,b], N, Ws). 
N = 2, 
Ws = [[a, b]] ; 
N = 1, 
Ws = [[a], [b]] ; 
% loops 

它因爲有相同的小片段:

length(Front, N), 
append(Front, _, L) 

With length/2,你繼續生成增加長度的列表;一旦FrontL更長,append/3失敗,length/2會產生一個更長的列表,等等。

其中一種方法是使用between/3約束前端的長度。如果你把它放在自己的斷言:

front_n(L, N, F) :- 
     length(L, Max), 
     between(1, Max, N), 
     length(F, N), 
     append(F, _, L). 

有了這個:

sliding_window(L, N, [L]) :- 
     length(L, N). 
sliding_window(L, N, [W|Ws]) :- 
     front_n(L, N, W), 
     L = [_|L0], 
     sliding_window(L0, N, Ws). 

而現在它終於作品:

?- sliding_window([a,b,c,d], 3, Ws). 
Ws = [[a, b, c], [b, c, d]] ; 
false. 

?- sliding_window([a,b,c], N, Ws). 
N = 3, 
Ws = [[a, b, c]] ; 
N = 1, 
Ws = [[a], [b], [c]] ; 
N = 2, 
Ws = [[a, b], [b, c]] ; 
false. 

練習:擺脫無害的,但不必要的選擇點。