2014-12-04 2 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

ответ

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

ли это улучшение или нет до вас ,

Смежные вопросы