【问题标题】:Accessing SWI-Prolog libraries from Logtalk从 Logtalk 访问 SWI-Prolog 库
【发布时间】:2013-05-15 16:49:49
【问题描述】:

我在使用 Logtalk 时玩得很开心,但在使用 phrase_from_file 时遇到了问题。具体来说,我的情况是这样的:

:- object(scan_parser).

   :- public(scanlist//1).
   scanlist([Scan|Scans]) --> scan(Scan), dcg_basics:blanks, scanlist(Scans).
   scanlist([]) --> [].

   :- public(scan_file/2).
   :- mode(scan_file(+filename, -scans), one).
   scan_file(Filename, Scans) :- pio:phrase_from_file(scanlist(Scans), Filename).

   ...
:- end_object.

问题在于对phrase_from_file 的调用。找不到scanlist,大概是因为它是这个对象的本地,所以我得到这个错误:

?- scan_parser::scan_file('input.txt', Scans).
ERROR: phrase/3: Undefined procedure: pio:scanlist/3

但是,如果我尝试使用这样的模块引用来扩大它:

scan_file(Filename, Scans) :- pio:phrase_from_file(::scanlist(Scans), Filename).

我收到此错误:

?- scan_parser::scan_file('input.txt', Scans).
ERROR: phrase/3: Undefined procedure: pio: (::)/3

如果我使用pio:phrase_from_file(this::scanlist(Scans), Filename)pio:phrase_from_file(scan_parser::scanlist(Scans), Filename) 也是一样。如果我在模拟 SWI 的模块设施时使用单个冒号,我会收到类似 ERROR: phrase/3: Undefined procedure: scan_parser:scanlist/3 的消息。

我认为这里的问题是 SWI 的 PIO 库正在尝试构建一些东西来交给phrase,它只是不够智能。但这是我经常想到的事情,使用phrase_from_file/2,我敢肯定还有其他时候我想从 SWI 的图书馆中挖掘一些东西并借用它。正确的前进方向是什么?我想尽可能保留 Logtalk 的封装性。

谢谢!

【问题讨论】:

  • 你好丹尼尔。您使用的是哪个 Logtalk 版本?
  • 我使用的是 2.44.1,但如果您认为那里可能没有问题,我会尝试使用 3.0。您可能还需要在错误变得明显之前创建“input.txt”。
  • 我强烈建议您迁移到 Logtalk 3.x。但是您偶然发现了 Logtalk 限制(与您使用的版本无关):不支持采用闭包的模块元谓词(请参阅用户手册中的 Prolog 迁移部分)。不过,让我考虑一下替代解决方案。
  • 3.0 HEAD 下的行为相同。
  • 问题的根源在于 Logtalk 通过(在其他转换中)在末尾添加单个参数(用于传递执行上下文)来编译对象谓词。这与使用采用闭包的模块元谓词冲突,因为模块将(通常通过直接或间接调用 call/N)附加附加参数以从闭包到目标,并且隐藏的执行上下文参数将被捕获中间(Prolog 模块系统不支持 Logtalk)。

标签: prolog dcg logtalk


【解决方案1】:

我正在为 Logtalk 3.x 设计一个通用解决方案,以支持将闭包作为元参数的 Prolog 模块元谓词。同时,您可以尝试以下(丑陋的)解决方法吗:

% ensure the module is loaded
:- use_module(library(pio)).


:- object(scan_parser).

    % override the non-standard meta-arguments declarations
    :- meta_predicate(pio:phrase_from_file(2,*)).

   :- public(scanlist//1).
   scanlist([Scan|Scans]) --> scan(Scan), dcg_basics:blanks, scanlist(Scans).
   scanlist([]) --> [].

   :- public(scan_file/2).
   :- mode(scan_file(+filename, -scans), one).
   scan_file(Filename, Scans) :- pio:phrase_from_file(user:scan_parser_scanlist(Scans), Filename).

    {scan_parser_scanlist(Scans, A, B)} :-
        phrase(scanlist(Scans), A, B).

    ...

:- end_object.

我无法测试,因为您只发布了部分目标代码。

【讨论】:

  • 谢谢!如果我遇到其他类似情况,我很高兴有一个解决方法。
  • 刚刚更新的 Logtalk 3.x HEAD 应该为您提供更快生成的 (:)/2 非终端代码,就像您发布的代码一样。
  • 在最新的 Logtalk 3.x HEAD 中解除了上述限制(关于调用 Prolog 模块元谓词将闭包作为元参数)。
  • Logtalk 3.00.0 Alpha 17 包括支持从对象和类别中调用的更改,包括 Prolog 内置元谓词和 Prolog 模块元谓词,它们将闭包作为元参数。您发布的代码应该可以按原样运行,无需任何解决方法。
猜你喜欢
  • 1970-01-01
  • 2016-09-03
  • 2019-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多