Как мне отфильтровать объявленные факты в зависимости от того, является ли одна переменная членом списка в Прологе?

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

Мне уже удалось заставить код читать текстовый файл, получать отдельные слова и определять, сколько раз каждое слово встречается в нем, так что это не проблема. Однако у меня возникают проблемы с фильтрацией слов, чтобы отображались только слова, которые встречаются в предварительно заданном списке.

Для некоторой идеи я объявляю слова фактами в базе данных 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 = []

Я прошу прощения, так как я знаю, что это довольно много текста для переваривания, но я чувствую себя довольно застрявшим, и я не совсем уверен, что делать дальше.

Любая помощь или руководство будет принята с благодарностью.

Было бы лучше, если бы вы использовали какую-то структуру данных «ключ-значение» для слов в предварительно определенном списке, а затем просмотрели слова в своем файле и буквально просто подсчитали их. Если вы готовы рассмотреть такое решение, я могу показать вам, как реализовать его в SWI-Prolog.

TA_intern 12.04.2023 13:40

Большое спасибо! Я определенно был бы готов рассмотреть подобное решение, если бы вы не возражали показать мне, как его реализовать, поскольку подсчет слов также поможет с более поздней функциональностью, которую я надеялся реализовать, когда определенное условие является либо истинным, либо ложным в зависимости от от количества использований ключевых слов в файле.

MattNewman2003 12.04.2023 15:48

Вероятно, вам следует задать новый вопрос, если вы хотите что-то другое...

TA_intern 13.04.2023 14:58
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
3
84
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Предикат 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 12.04.2023 14:53

@TA_intern Да! За исключением того, что переменная Predefined должна быть создана в запросе, прежде чем использоваться в member/2.

slago 12.04.2023 14:56

Большое спасибо за Вашу помощь! Итак, прав ли я, говоря, что крайний левый параметр findall, который я ранее считал шаблоном элемента, который я хотел найти в Prolog, на самом деле является единственным способом вывода элемента?

MattNewman2003 12.04.2023 16:04

@ MattNewman2003 Да, верно!

slago 12.04.2023 18:08

findall(word(W, X), member(W, PredefinedWords), MatchingWords).

Это должно быть:

findall(word(W, X), (word(W, X), member(W, PredefinedWords)), MatchingWords).

Другие вопросы по теме