2013-11-21 3 views
3

Я новичок в прологе программирования, и я надеюсь, что вы скромны и помочь мне пройти эту путаницуСумма элементов в списке в Прологе необходимо небольшое пояснение

Я столкнулся с проблемой, чтобы вычислить сумму в прологе и У меня есть ответ, но мне это не очень понятно. Ответ:

list_sum([], 0). 
list_sum([Head | Tail], Total) :- 
    list_sum(Tail, Sum1), 
    Total = Head + Sum1. 

, что я не понимаю, что такое Sum1 и как программа будет работать на этапах

это первый будет проверить первое условие list_sum([], 0). пока условие не соблюдено это будет разделите список на 2 части Head и Tail?


Надеюсь, вы примете маленького новичка и дайте ему некоторое время, чтобы исправить его смущение.
Благодарю вас, ребята,

ответ

4

Это классический рекурсивный подход - вам нужно научиться понимать Пролог.

В вашем правиле есть два предложения - одно для пустого списка, а одно для непустого. В предложении пустого списка указано, что сумма элементов пустого списка равна нулю (что вполне разумно). Это называется «базовым случаем рекурсии». Каждое конечное рекурсивное правило должно иметь базовый регистр.

Вторая статья немного сложнее. В нем говорится примерно так: «вычислить сумму элементов в непустом списке, сначала отрубить начальный элемент и вычислить сумму элементов в более коротком списке, который будет получен. Вызвать эту сумму Sum1. Теперь вычислите Total, добавив значение начального элемента до значения Sum1.

Второе предложение рекурсивно разлагает список на ряд более коротких списков, пока они не попадут в пустой список. В этот момент вступает первый пункт, предусматривающий сумму . пустой список

Рассмотрим следующий пример:

list_sum([12, 34, 56], X) 
    list_sum([34, 56], <unknown-1>) 
     list_sum([56], <unknown-2>) 
      list_sum([], 0)   ---> succeeds with Total bound to 0 
     <unknown-2> becomes 0 + 56 ---> succeeds with Total bound to 56 
    <unknown-1> becomes 0 + 56 + 34 ---> succeeds with Total bound to 90 
X becomes 0 + 56 + 34 + 12   ---> succeeds with X bound to 102 

Это работает, потому что каждый уровень вызова в рекурсивной цепочке получает свою собственную переменную для Sum1. Эти значения начинаются без ограничений, но после того, как рекурсивная цепочка вызовов «выйдет из строя», Sum1 s начнет получать значения, вычисленные каждым предыдущим уровнем. В конце концов цепочка вызовов достигает верхнего уровня, связывая конечный результат с переменной, переданной вызывающим.

+0

Полностью оценить его. Большое спасибо . Будьте здоровы . Мне было слишком трудно понять это в первом. Но вы все упростили для меня – user3018890

+0

Хорошее объяснение, но «возвращение с 102» и т. Д. Немного вводит в заблуждение, особенно для тех, кто привык думать сообразительно. Предложения Prolog не возвращают значения; они вообще не «возвращаются». Было бы точнее сказать что-то вроде «преуспевает с« Х », связанным с 102» и т. Д. –

+0

@TedHopp Я тоже об этом подумал - возврат немного вводит в заблуждение. Я добавил «с», пытаясь предположить, что значение не возвращается в процедурный смысл. Мне нравится ваша формулировка лучше, чем моя, хотя, спасибо за отличный комментарий! – dasblinkenlight

5

В вашей программе есть небольшая ошибка. Строка Total = Head + Sum означает, что Total является структурой + с двумя аргументами. Вероятно, вы имеете в виду is вместо =, что означает арифметическую оценку. Но лучше всего использовать #=.

На ваш вопрос вы задаете , что программа сделает. Это довольно разумный вопрос в командно-ориентированных («императивных») языках, поскольку единственное значение, которое вы можете вывести из программы, - это пошаговое действие. Но здесь, в Prolog, все немного по-другому. Вы все же можете попытаться применить это пошаговое мышление, но рано или поздно вы поймете, что здесь все может стать чрезвычайно сложным, просто потому, что у Пролога нет одного потока управления, но два одновременно вызываются (AND- и OR- контроль). И даже «структуры данных» различны ...

Но есть способ прочитать программу Prolog, которая не имеет аналогов в императивных языках: вы можете понимать программу как отношение между аргументами. Таким образом, вы можете сосредоточиться на том, как выглядит отношение по процедурным аспектам. В конце концов, если описанное отношение неверно, нет смысла спрашивать, как это делает программа.

Итак, позвольте мне перефразировать свою программу:

:- use_module(library(clpfd)). 
list_sum([], 0). 
list_sum([E|Es], S) :- 
    S #= E+T, 
    list_sum(Es, T). 

это первый проверит первое условие list_sum ([], 0). в то время как условие не выполняется, оно будет делить список на 2 части H и T тогда?

Ваш вопрос подразумевает, что существует единственный поток управления («хотя это такая типичная конструкция, которая подразумевает это»). Но это может также работать по-другому. Рассмотрим запрос:

?- list_sum(Xs,0). 
Xs = [] ; 
Xs = [0] ; 
Xs = [_G1710, _G1713], 
_G1710+_G1713#=0 ... 

Здесь мы задаем Что списки существует, сумма которых равна 0. Теперь ваше «время» больше не имеет смысла.

Ответы, которые мы получаем: пустой список; список с 0; список из двух элементов, где сумма элементов равна 0; и т.д ...

Лучший способ понять такие программы, чтобы читать их как отношения, как так:

list_sum([], 0: Пустой список имеет сумму 0.

правило теперь гласит лучший в направлении стрелки :- то есть справа налево:

  • list_sum(Es, T).: * Предоставлено Es список с суммой T и ...

  • S #= E+T: ... S это E плюс T ...

  • :- ... то мы можем заключить, что ...

  • list_sum([E|Es], S): S - сумма, содержащая список [E|Es].

Таким образом, это можно понять, не обращая слишком много внимания на процедурные детали. Это больше похоже на понимание термина, см. .

+0

Да, я просто заметил это. и спасибо за объяснение – user3018890

+1

+1, я очень рекомендую этот стиль для чтения предикатов и использования ограничений конечного домена для целочисленной арифметики. – mat

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