如何使用多个解决方案编写pyswip外部谓词?

2024-09-20 22:21:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图编写一个python方法,当暴露于prolog时,它有多种解决方案。我想我可以使用registerForeign,但是项目的例子没有说明它是否可以实现。下面是我想做的一个人为的例子:

设想一个谓词active_user(X)将X统一到网站上的每个活动用户。然后在我的序言中,我可以通过其他谓词进一步过滤X,即active_user(X), max_level(X)

active_user的python定义可能如下所示:

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")

examples目录包含registerForeign的简单用法,但它不处理这种情况。 我提出的唯一可行的解决方案是提前进行查询,然后在循环中使用prolog.assertz断言这些值。但这并没有我想象的那么灵活

多谢各位

编辑:“george”不起作用,因为它是一个字符串(可能是一个单独的问题),但统一一个整数在这种情况下确实起作用


Tags: 方法getserverdefusername解决方案usersprolog
1条回答
网友
1楼 · 发布于 2024-09-20 22:21:10

尽管我的答案来得有点晚,但我面临着一个非常类似的问题。因此,我决定分享我的解决方案

您需要设置标志PL_FA_NONDETERMINISTIC来注册非确定性谓词。否则,它将默认注册为确定性谓词。此外,还需要一个参数来跟踪调用外部谓词的上下文。例如,如果谓词具有arity 2,则需要3个参数,其中两个用于谓词本身的参数,另一个用于上下文

在谓词内部,您需要提取调用的当前上下文(PL_FIRST_CALLPL_REDO、或PL_PRUNED),如果适用,还需要提取在上一次调用中返回到Prolog的任何信息(返回时使用PL_retry,访问时使用PL_foreign_context)。该机制类似于SWI文档(https://www.swi-prolog.org/pldoc/man?section=foreignnondet)中为C谓词描述的机制。对于pyswip的用法,您需要检查源代码(https://github.com/yuce/pyswip

下面是使用非确定性谓词返回用户列表的代码。我使用Python 3.8.3(Anaconda)和GitHub(2020年7月20日)的最新pyswip代码对其进行了测试

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'}]

相关问题 更多 >

    热门问题