Можно ли написать пустой список как список различий в Prolog?
Пустые списки... странные, новичкам Пролога, как я. Я бы сказал, что невозможно написать пустой список []
как список различий T1-T2
так же, как невозможно записать атом как список различий. Однако я бы предположил, что для использования рекурсии должен существовать способ использования []
в настройке списка различий. У меня есть Google для этого, но я не могу найти ответ, и Братко (Prolog Programming for AI) лишь кратко затрагивает тему.
Итак, можно ли написать пустой список как список различий в Prolog, если да, то как и когда это было бы полезно?
Ответы
Ответ 1
Проблемы с пониманием этой темы обычно связаны с использованием вводящей в заблуждение терминологии.
Как рекомендовано в tutorial.pdf и особенно pap95.pdf используйте, например, список разницу или просто разницу.
Раздел 5 Преподаватели начинающих Prolog содержат соответствующие причины.
Пустой список однозначно обозначается атомом []
.
Обратите внимание, что различие в списках всегда означает рассуждение о двух списках, и из-за этой категориальной разницы между одним и несколькими списками вы можете лучше найти какую-либо переписку или аналогию, но не идентичность между пустым списком и разницей в списке.
Я полностью поддерживаю мнение, выраженное в вышеприведенном документе, что вы должны сосредоточиться на с использованием DCGs, по крайней мере, вначале. Рассуждение о различиях явно придет естественным образом позже.
Ответ 2
Добавление двух различий в списке означает просто объединение первого указателя конца diff со второй головкой. С регулярными списками требуется повторная проверка всей структуры списка первого списка. Таким образом, повторное конкатенация справа линейна по методу разности списков и квадратична с обычными списками.
Когда все запланированные конкатенации завершены, чтобы вернуть всю структуру в виде простого списка вызывающему, мы просто объединяем логвар "конечный указатель" с []
.
В терминах C различие списков - это часть односвязного списка, где мы сохраняем две переменные: указатель на голову, а также его указатель на хвост:
// typedef struct { int payload; node* next } node;
typedef struct { node** head; node** tail } list_diff;
Теперь каждая конкатенация - это просто назначение конечного указателя:
void diff_concat( list_diff* a, list_diff* b)
{
*(a -> tail) -> next = *(b -> head);
a -> tail = b -> tail;
}
И финализация
void diff_finalize( list_diff* a)
{
*(a -> tail) = NULL; // or some sentinel value, whatever
}
В Prolog мы могли бы представить его как двоичный термин, например -/2
, например. -(A,B)
или A-B
.
Но (как и в C) нет реальной необходимости создавать фактическую структуру в памяти только для удерживания двух указателей; мы можем просто поддерживать два логарифма в отдельности. Или пусть DCG сделают это для нас.
Выше было мотивированное введение в список разностной техники, "для чего они хороши?". Также ясно, что представление пустой разности
list_diff* d;
*(d -> head) = *(d -> tail);
Или в Prolog, пара логарифмов, унифицированных друг с другом: L-L, var(L)
. Чтобы узнать, почему, посмотрите, что происходит, когда пустой diff добавляется с некоторым другим различием справа (всегда справа мы добавляем вещи, тем самым увеличивая списки сверху вниз). Мой C может быть выключен, идея состоит в том, что, установив хвост, добавление к пустому diff также обновит его голову.