Я относительно новичок в программировании на Прологе, и я пытаюсь создать программу, которая читает текстовый файл, находит слова в файле, а также количество вхождений каждого слова, находит слова в файле, которые соответствуют предварительному -определенный список слов и определяет статус файла в зависимости от того, сколько раз слова из предварительно определенного списка используются в файле.
Мне уже удалось заставить код читать текстовый файл, получать отдельные слова и определять, сколько раз каждое слово встречается в нем, так что это не проблема. Однако у меня возникают проблемы с фильтрацией слов, чтобы отображались только слова, которые встречаются в предварительно заданном списке.
Для некоторой идеи я объявляю слова фактами в базе данных Prolog в формате:
word(W, X)
где W — само слово, а X — количество раз, которое оно встречается в файле.
Например, если я прочитаю текстовый файл со следующим текстом:
It's a lovely day outside; it's so hot and sunny, and it's overall lovely!
а затем выполните следующий запрос:
forall(word(W, X), writeln(W+X)
Запрос работает успешно, вывод:
It's+1
a+1
day+1
outside+1
so+1
hot+1
sunny+1
and+2
it's+2
overall+1
lovely+2
В настоящее время он выглядит не самым красивым, и он также чувствителен к регистру, но я считаю, что он успешно читает файл и успешно вычисляет количество использований слова.
Однако у меня возникают проблемы, если я пытаюсь отфильтровать слова, чтобы отобразить только те, где W соответствует слову в предварительно определенном списке слов, например:
PredefinedWords = [hot, sunny, cold, rainy]
Я провел поиск в Интернете, и, исходя из этого, моей первоначальной идеей было использовать предикаты findall и member в следующем запросе:
findall(word(W, X), member(W, PredefinedWords), MatchingWords).
Я надеялся, что применительно к приведенному выше примеру он отфильтрует предварительно объявленные слова, найденные в файле, и вернет результат, который выглядит примерно так:
MatchingWords = [word(hot, 1), word(sunny, 1)]
Однако, когда я фактически выполнил запрос, результат был примерно таким:
MatchingWords = [word(hot, _), word(sunny, _), word(cold, _), word(rainy, _)]
Я обнаружил, что он просто воспроизводит каждый элемент заранее определенного списка в формате word(W, X), где W — элемент списка, а X — пустая переменная. Он вообще не использовал слова, найденные в файле.
Когда я поместил аналогичный запрос в предикат в консультируемом файле, я понял, что Пролог рассматривает слово (W, X), объявленное в этом запросе, как нечто совершенно иное, чем в более ранних запросах, даже когда приведенный выше запрос в тот же предикат считал слово (W, X) таким же, как и в предыдущих запросах. В отличие от других запросов, таких как forall, запрос findall вообще не использует ранее объявленные слова. Меня это немного смутило, но я решил попробовать что-то другое.
Поэтому я решил вместо этого попробовать сопоставить слова и их частоты во вложенном списке, как я сделал для сортировки слов по частоте, используя следующий запрос:
findall([W, X], word(W, X), WordsList)
Этот код работал так, как предполагалось, и отображал слова и соответствующие им частоты во вложенный список с именем WordsList.
Со словами, отображенными в список, я решил повторить поисковый запрос со следующим форматом:
findall(WordsList, member(0, PredefinedWords), MatchingWords).
Я надеялся, что этот запрос вернет все члены списка WordsList, где первый индекс списка (слово) был найден в списке предопределенных слов, и запишет их в новый список MatchingWords.
Однако он просто вывел MatchingWords как пустой список:
MatchingWords = []
Затем я подумал, не запутался ли он, потому что я не объявлял конкретный формат индекса списка, поэтому я попробовал это:
findall(WordsList[W, X], member(W, PredefinedWords), MatchingWords).
Однако это вызвало синтаксическую ошибку «Ожидается оператор», где [ после WordsList является оскорбительным символом.
Наконец, я провел еще несколько поисков и попробовал включить предикат с лямбда-функцией в следующем запросе:
include(([W, X]>>member(W, PredefinedWords)), WordsList, MatchingWords).
Однако он снова вернул пустой список:
WordsList = MatchingWords, MatchingWords = []
Я прошу прощения, так как я знаю, что это довольно много текста для переваривания, но я чувствую себя довольно застрявшим, и я не совсем уверен, что делать дальше.
Любая помощь или руководство будет принята с благодарностью.
Большое спасибо! Я определенно был бы готов рассмотреть подобное решение, если бы вы не возражали показать мне, как его реализовать, поскольку подсчет слов также поможет с более поздней функциональностью, которую я надеялся реализовать, когда определенное условие является либо истинным, либо ложным в зависимости от от количества использований ключевых слов в файле.
Вероятно, вам следует задать новый вопрос, если вы хотите что-то другое...
Предикат findall(+Template, :Goal, -Bag) создает список экземпляров, которые Template
последовательно получает при возврате к Goal
, и объединяет этот список с Bag
. На самом деле Template
— это не предикат, а просто термин, определяющий, как должны быть структурированы собранные данные.
Предполагая, что предикаты word/2
и keywords/1
определены, вы можете использовать их для определения предиката keyword/2
следующим образом:
keyword(Word, Counter) :-
keywords(Keywords),
member(Word, Keywords),
word(Word, Counter).
keywords([hot, sunny, cold, rainy]).
word('It\'s', 1).
word(a, 1).
word(day, 1).
word(outside, 1).
word(so, 1).
word(hot, 1).
word(sunny, 1).
word(and, 2).
word('it\'s', 2).
word(overall, 1).
word(lovely, 2).
Пример:
?- keyword(W, C).
W = hot,
C = 1 ;
W = sunny,
C = 1 ;
false.
Затем, используя предикаты keyword/2
и findall/3
, вы можете спросить:
?- findall(word(W,C), keyword(W,C), L).
L = [word(hot, 1), word(sunny, 1)].
?- findall(W-C, keyword(W,C), L).
L = [hot-1, sunny-1].
?- findall([W,C], keyword(W,C), L).
L = [[hot, 1], [sunny, 1]].
?- findall(frequency(W,C), keyword(W,C), L).
L = [frequency(hot, 1), frequency(sunny, 1)].
Примечание. Как уже указывалось в предыдущем комментарии, было бы лучше просто подсчитывать ключевые слова по мере чтения файла. В любом случае, смысл этого ответа в том, чтобы прояснить, как использовать findall/3
.
Однострочник, который делает то же самое, будет: findall(word(W, C), ( member(W, Predefined), word(W, C) ), Result)
. Но да, это не очень хорошая идея в целом.
@TA_intern Да! За исключением того, что переменная Predefined
должна быть создана в запросе, прежде чем использоваться в member/2
.
Большое спасибо за Вашу помощь! Итак, прав ли я, говоря, что крайний левый параметр findall, который я ранее считал шаблоном элемента, который я хотел найти в Prolog, на самом деле является единственным способом вывода элемента?
@ MattNewman2003 Да, верно!
findall(word(W, X), member(W, PredefinedWords), MatchingWords).
Это должно быть:
findall(word(W, X), (word(W, X), member(W, PredefinedWords)), MatchingWords).
Было бы лучше, если бы вы использовали какую-то структуру данных «ключ-значение» для слов в предварительно определенном списке, а затем просмотрели слова в своем файле и буквально просто подсчитали их. Если вы готовы рассмотреть такое решение, я могу показать вам, как реализовать его в SWI-Prolog.