List Prolog-列表中的数字之和

List Prolog-列表中的数字之和,list,prolog,List,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)). su

我对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).

希望这不是完全错了。再次感谢

我将采用以下方法: 将给定列表分为两个数字和字母列表,将数字相加并附加到字母列表中:

% 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).

这不是最理想的方法,但它在逻辑上简单明了。

您使用的变量很少。Prolog是一种声明性语言,一旦设置了变量,就不能更改它。如前所述,
Z是Z+X
仅当
X=0
时才为真。因此,如果xxxx/y与…相统一,那么大多数谓词文档都以
true开头

在大多数情况下,列表递归的基本情况是空列表
[]
,而不是单元素列表
[X]
。在大多数情况下,它只会使您的程序复杂化,甚至更糟的是,在回溯之后添加解决方案

这些是您在浏览列表时需要处理的情况

  • 列表是空的→ 返回列表
    [0]

  • 头是一个数字→ 返回上一个结果加上找到的数字

  • 头不是数字→ 在上一个结果的编号之后将其添加到列表中

  • 这样,您就可以始终确保输出列表的第一个元素是数字。谓词最好写成
    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]).
    

    在prolog中,一旦将变量绑定到值,它就不再是变量。这意味着您需要在递归列表时维护调用堆栈上的状态。所以我会像这样处理这个问题,使用带有额外参数的helper谓词,这些参数在运行时维护状态

    该约定通常用于帮助程序,使其具有与“public”谓词相同的functor,并具有维护状态所需的额外值。我会这样处理:

    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)
      .
    

    这是否是一种改进取决于您。

    在Prolog中,只有当X=0时,Z为Z+X才能为真