【问题标题】:List processing in Prolog using a C++ interface使用 C++ 接口在 Prolog 中处理列表
【发布时间】:2014-07-08 21:40:46
【问题描述】:

我正在尝试处理从 Qt 制作的 GUI 界面获得的数字列表。具体来说,我想在一个标签中向用户返回一个包含所有数字的列表,这些数字甚至在他的输入列表中。感谢用户 CapelliC,我设法包含了所有文件和库,以使 SWI-Prolog 在 C++ 内部工作,我现在正在尝试开发该程序。

要求我使用 Prolog 的 C++ 接口,以便我通过 QLineEdit 对象从用户接收列表,将列表发送到 Prolog 引擎,然后 Prolog 应该将结果返回给 C++ 程序对的列表。

我已经制定了从列表中提取对并将其作为另一个列表返回的规则。这些是我的 manejoListas.pl 文件的内容,我的程序的 SWI-Prolog 知识库:

pares(Lista,ListaPares):-findall(Numero,(member(Numero,Lista),mod(Numero,2)=:=0),ListaPares).

这在 SWI-Prolog 中可以正常工作。现在,我想在我的基于 C++ 和 Qt 的程序上加载这个 .pl 文件,将输入列表发送到这个规则并获得结果列表,由参数 ListaPares 指向我的 C++ 接口,以便我可以将其展示给用户。

我已阅读外语界面文档,但无法找到解决此特定场景所需的内容。到目前为止,这是我盲目地基于一个不完整的“教程”,我在 youtube 上发现有人懒得解释他为另一个不相关的问题做了什么,主要是使用 Qt、C++ 和序言。

void MainWindow::on_btnPares_clicked()
{
    QString listaEntrada = ui->txtListaEntrada->text();    

    term_t listaEntrada, listaPares, term;
    functor_t paresFunc;

    listaEntrada = PL_new_term_ref();


    listaPares = PL_new_term_ref();

    term = PL_new_term_ref();

    PlCall("consult('manejoListas.pl')"); //I assume this opens my knowledgebase file so that i can work with it

    paresFunc = PL_new_functor(PL_new_atom("pares"), 2);

    PL_cons_functor(term, paresFunc, listaEntrada, listaPares);

    if(PL_call(term, NULL)) {
        PL_get_string()
    }


}

我无法前进,我不知道如何将列表传递给 SWI-Prolog,甚至不知道如何构建我应该发送给 Prolog 的正确咨询或如何接收答案。该程序的行为应该与我向 SWI-Prolog 运行以下咨询完全一样:

?- pares([2,4,8,9],X).
X = [2, 4, 8].

提前感谢您提供的任何帮助。

【问题讨论】:

    标签: c++ qt prolog swi-prolog


    【解决方案1】:

    最好避免混合 C 接口 - 即 term_t、functor_t、PL_new_term_ref() 等 - 和 C++ - 即 PlCall() 等。

    您的代码现在显然不可编译 - 也许您对复杂性感到有些沮丧,但请深呼吸并继续研究文档...

    参见PlTail 类文档页面,这里有一个构建列表所需代码的简单示例。 OTOH,如果您可以假设列表在语法上是正确的,那么一些更高级别的内置可以使您的任务更简单。例如,这个 sn-p 需要一个以逗号分隔的数字形式的输入列表:

    try {
        QString numbers = QInputDialog::getText(0, "Input numbers separed by comma", "Numbers");
        PlTerm SQLIST = PlAtom(qPrintable("[" + numbers + "]")), NUMLIST, _, SUM;
        if (PlCall("atom_to_term", PlTermv(SQLIST, NUMLIST, _))) {
            if (PlCall("sum_list", PlTermv(NUMLIST, SUM))) {
                QMessageBox::information(0, "sum",
                    QString("as string: %1\nas number: %2").arg((const char*)SUM).arg((long)SUM));
            }
        }
    }
    catch(PlException ex) {
        QMessageBox::critical(0, "exception", (const char*)ex);
    }
    

    然后展示如何取回值 - C++ 接口使用特定样式进行类型转换和值提取。使用这种风格,我们可以获得非常紧凑的代码,即使在 Prolog 和 C++ 之间存在很大的“阻抗不匹配”的情况下(但这里我展示了扩展代码,没有我通常使用的任何快捷方式)。

    注意 try/catch 块:它可以避免很多问题,捕获语法和语义错误 - 就像在 Prolog 交互式 shell 中一样。

    最后一个提示:始终测试 PlCall 的返回 - 有时,您的代码可能会失败无异常...

    【讨论】:

    • 明白。但我看不到如何在文档中加载 .pl 文件。如果我使用 PlCall 加载包含规则和事实的文件是否正确?例如:首先调用 PlCall 以使用 working_directory 谓词将工作目录更改为具有 .pl 文件的文件夹,以便我稍后可以调用 Consult('nameoffile.pl') 来打开它?
    • 另外,我不明白这行代码怎么没有给你一个错误:PlTerm SQLIST = PlAtom(qPrintable("[" + numbers + "]")), NUMLIST, _,和;这里到底发生了什么?我可以理解您正在将一个包含输入列表的原子分配给一个术语,但是 NUMLIST、_ 和 SUM 呢?这些是变量吗?那么下划线呢? sum_list 只允许两个参数:列表和存储结果的变量
    • 我想我理解错了。您在该行中所做的是声明三个术语:第一个是原子,第二个是变量,第三个是匿名变量。我说的对吗?
    • 对不起 cmets 的数量,最后一个问题:这一行 PlCall("atom_to_term", PlTermv(SQLIST, NUMLIST, _)) 这行做什么?我搜索atom_to_term谓词的目的是什么,即“返回NUMLIST中的读取项和_中的变量绑定”,但是您在代码中使用它是什么?
    • 1) 是的,就像使用命令行一样。 2) 在 Prolog 中,我们只有一个数据结构 - 一个术语 - 在 C++ 中它是 PlTerm,它是 term_t 上的一个小包装器,它是 C 接口公开的本机处理程序。该行声明了 4 个术语。我对term_to_atom/3 返回的绑定不感兴趣,然后使用_。 3) 都是术语。正如您正确猜测的那样,有些是变量。 4) 在 2) 中回答。我可以补充一点,atom_to_term/3 实现了一个 general Prolog 解析器 - 一个强大的东西
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多