2014-12-04 70 views
-1

我對Prolog非常陌生,仍然在爲語言的語法而苦苦掙扎。我試圖編寫一個函子,它通過列表來查看並創建一個新列表,頭部是列表中所有數字的總和,尾部是其中的任何內容。Prolog - 列表中的數字總和

例如,[1,2,a,3,b,c,4] = [10,a,b,c]。

現在,我擔心我的代碼非常粗糙,但如果有人能指出我的方向正確,我將非常感激。

sumOfNumbers([X], Z) :- 
    number(X), 
    Z is Z+X. 
sumOfNumbers([X], _) :- 
    not(number(X)). 
sumOfNumbers([X|Rest], Z) :- 
    number(X), 
    Z is Z+X, 
    sumOfNumbers(Rest, Z). 
sumOfNumbers([X|Rest], Z) :- 
    not(number(X)), 
    sumOfNumbers(Rest, Z). 

希望這不是完全脫離基地。再次感謝

+2

在Prolog中,Z是Z + X只有當X = 0時才爲真 – CapelliC 2014-12-04 22:06:30

回答

0

我會採取這種做法: 單獨給定的列表中數字和字母的兩個列表,總結了數字和附加的字母列表:

% Sum of list of numbers 
% sum(+List, -Sum) 
sum([], 0). 
sum([H|T], S) :- 
    sum(T, S1), 
    S is H + S1. 

% Separate a list into two lists one of numbers and second of non-numbers 
% separate(+InputList, -Numbers, -Letters) 
separate([], [], []). 
separate([H|T], [H|N], L) :- 
    number(H), 
    separate(T, N, L). 
separate([H|T], N, [H|L]) :- 
    separate(T, N, L). 

% This is your function 
sumOfNumbers(L, [Sum | Letters]) :- 
    separate(L, Numbers, Letters), 
    sum(Numbers, Sum). 

這不是最優化的方法,但它在邏輯上簡單明瞭。

0

您正在使用的變量很少。 Prolog是一種聲明性語言,一旦它被設置就不能改變它。如CapeliiC已經指出,Z is Z + X只有如果X = 0爲真。出於這個原因,大多數謂詞的文檔以true if xxxx/y unifies with…開頭。

列表遞歸的基本情況在大多數情況下是空列表[],而不是一個元素列表[X]。在大多數情況下,這隻會讓你的程序變得複雜,甚至更糟,在回溯之後添加解決方案。

這些是您在瀏覽列表時需要處理的情況。

  1. 列表爲空→返回一個列表[0]

  2. 頭是一個數字→返回先前的結果加上發現號

  3. 頭是不是一個數字→添加它到前一個結果的編號後的列表中。

這樣,您總是確保您有一個數字作爲輸出列表的第一個元素。由於第一個元素僅僅是另一個參數,因此謂詞會更好地寫入,因爲sumOfNumbers(Input, Sum, Rest)不會被分心。

所以這裏是程序:

sumOfNumbers([],[0]). 
sumOfNumbers([X|R],[Z|A]):- 
    number(X),    % cut here 
    sumOfNumbers(R,[Y|A]), 
    Z is Y + X. 
sumOfNumbers([X|R],[Y,X|A]):- 
    \+ number(X),   % cut here 
    sumOfNumbers(R,[Y|A]). 

您可以添加(綠色)切後運營商的數量進行檢查,以防止失敗重做。

我個人比較喜歡,如果檢查的這兩種情況下會出現使用->操作和結構是相似的:

sumOfNumbers2([],[0]). 
sumOfNumbers2([X|R],Out):- 
    sumOfNumbers2(R,[Y|A]), 
    (number(X)->    % read as if X is a number 
     Z is Y + X, 
     Out = [Z|A]; 
    Out =[Y, X|A]). 
0

在序言中,一旦你綁定變量的值,它停止變量爲。這意味着您需要在調用列表時維護調用堆棧的狀態。所以我會這樣處理這個問題,使用一個助手謂詞和額外的參數來保持狀態。

約定通常是爲幫助者具有與「公共」謂詞相同的函子,並具有維護狀態所需的額外值。我想接近它是這樣的:

sum_of_numbers(Xs,Ys) :-  % to sum the numbers in a list, 
    sum_of_numbers(Xs,0,[],Ys) % we invoke the helper, seeding its two accumulators appropriately. 
    . 

sum_of_numbers([]  , T , L , [T|L]) . % when the source list isexhausted, unify the accumulators with the result 
sum_of_numbers([X|Xs] , T , L , R ) :- % otherwise, 
    number(X) ,        % - if X is numeric 
    T1 is T+X ,        % - increment the tally 
    sum_of_numbers(Xs,T1,L,R)     % - and recurse down 
    .           % 
sum_of_numbers([X|Xs] , T , L , R ) :- % otherwise, 
    \+ number(X) ,       % - if X is non-numeric 
    sum_of_numbers(Xs,T,[X|L],R)    % - add X to the list accumulator 
    .           % - and recurse down. 

您也可以使用軟切(隱含的)第2及3組合:

sum_of_numbers([]  , T , L , [T|L]) . 
sum_of_numbers([X|Xs] , T , L , R ) :- 
    (number(X) -> 
    T1 is T+X , L1 = L 
    ; 
    T1 = T , L1 = [X|L] 
) , 
    sum_of_numbers(Xs,T1,L1,R) 
    . 

這是否是一種進步與否是由你。