Как написать внешний предикат pyswip с несколькими решениями? - PullRequest
0 голосов
/ 25 мая 2020

Я пытаюсь написать метод python, который при открытии пролога имеет несколько решений. Я думал, что могу использовать registerForeign, но примеры проекта не указывают, можно ли это сделать. Вот надуманный пример того, что я хочу сделать:

Представьте себе предикат active_user(X), который объединяет X для каждого активного пользователя на веб-сайте. Затем в моем прологе я мог бы дополнительно отфильтровать X по другим предикатам, например active_user(X), max_level(X)

Определение python для active_user могло бы выглядеть так:

def active_users(username):
  active_users = server.get_active_users() # List of strs
  for a in active_users:
    username.unify(a)
    yield

Выше, конечно , не работает. Вот еще один подход, который я пробовал:

def active_users(username):
  username = list(server.get_active_users())

Это тоже не сработало. Однако приведенный ниже пример работает:

def active_users(username):
  username.unify("george")

Каталог примеров содержит простое использование registerForeign, но не обрабатывает этот случай. Единственное рабочее решение, которое я придумал, - это сделать запрос заранее, а затем подтвердить эти значения, используя prolog.assertz в al oop. Но это менее гибко, чем то, что я себе представляю.

Спасибо

РЕДАКТИРОВАТЬ: "george" не работает, потому что это строка (возможно, отдельный вопрос), но объединяет целое число в этом случае работает.

1 Ответ

0 голосов
/ 29 июля 2020

Хотя мой ответ пришел немного поздно, я столкнулся с очень похожей проблемой. Поэтому я решил поделиться своим решением.

Вам нужно установить флаг PL_FA_NONDETERMINISTIC, чтобы зарегистрировать недетерминированный предикат c. В противном случае он будет зарегистрирован как предикат детерминизма c по умолчанию. Кроме того, вам понадобится еще один параметр, чтобы отслеживать контекст вызова вашего внешнего предиката. Например, если ваш предикат имеет арность 2, вам понадобятся 3 параметра, два для аргументов самого предиката и один дополнительный для контекста.

Внутри вашего предиката вам необходимо извлечь текущий контекст вызова (PL_FIRST_CALL, PL_REDO или PL_PRUNED) и, если применимо, любую информацию, которую вы вернули в Prolog в предыдущем вызове (верните с помощью PL_retry и получите доступ с помощью PL_foreign_context). Этот механизм аналогичен описанному для C предикатов в документации SWI (https://www.swi-prolog.org/pldoc/man?section=foreignnondet). Для использования с pyswip необходимо проверить исходный код (https://github.com/yuce/pyswip).

Ниже приведен код для возврата списка пользователей с использованием недетерминированного предиката c . Я тестировал его, используя Python 3.8.3 (Anaconda) и самый последний код pyswip с GitHub (20 июля 2020 г.).

import pyswip


users = ["George", "Paul", "John", "Ringo"]


def active_users(username, handle):

    control = pyswip.core.PL_foreign_control(handle)

    index = None
    return_value = False

    if control == pyswip.core.PL_FIRST_CALL:  # First call of active_users
        index = 0

    if control == pyswip.core.PL_REDO:  # Subsequent call of active_users
        last_index = pyswip.core.PL_foreign_context(handle)  # retrieve the index of the last call
        index = last_index + 1

    if control == pyswip.core.PL_PRUNED:  # A cut has destroyed the choice point
        # Here we could do some clean up (not needed in this simple example)
        pass

    if index >= 0 and index < len(users):
        username.unify(users[index])
        return_value = pyswip.core.PL_retry(index)  # This allows us to retrieve the correct index in the next call to active_users

    return return_value


pyswip.registerForeign(active_users, arity=1, flags=pyswip.core.PL_FA_NONDETERMINISTIC)

prolog = pyswip.Prolog()

print(list(prolog.query("active_users(X)")))

При запуске кода вы должны получить следующий результат:

[{'X': 'George'}, {'X': 'Paul'}, {'X': 'John'}, {'X': 'Ringo'}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...