2014-12-04 61 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) 
    . 

这是否是一种进步与否是由你。