跨模块的“接口"调用 SWI-Prolog [英] A cross-module "interface" call in SWI-Prolog

查看:57
本文介绍了跨模块的“接口"调用 SWI-Prolog的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能特定于 SWI Prolog 模块系统.

This may be specific to the SWI Prolog module system.

假设我们有三个 Prolog 模块(在 SWI-Prolog 模块系统中):

Suppose we have three Prolog modules (in the SWI-Prolog module system):

  • robin(在文件 robin.pl 中)
  • arthur(在文件 arthur.pl 中)
  • helper(在文件 helper.pl 中).
  • robin (in file robin.pl)
  • arthur (in file arthur.pl)
  • helper (in file helper.pl).

谓词robin:robin/0(即robin模块中的谓词robin_hood/0)和谓词arthur:arthur/0 调用谓词helper:helper/2(由模块helper导出).

Predicates robin:robin/0 (i.e. predicate robin_hood/0 in module robin) and predicate arthur:arthur/0 call predicate helper:helper/2 (which is exported by module helper).

谓词 helper:helper/2 然后应该调用谓词 toolshed/1,这取决于调用者模块不同.我希望 helper/2 调用与调用 helper/2 的谓词关联的 toolshed/1 谓词.

Predicate helper:helper/2 then should call a predicate toolshed/1, which is different depending on the caller modules. I would like helper/2 to call the toolshed/1 predicate associated with the predicate that calls helper/2.

在 Java 中,可以将带有 toolshed() 方法的接口传递给 helper(),以便 helper() 可以调用接口并最终实现正确的实现.

In Java, one would pass an interface with a toolshed() method to helper(), so that helper() can call the interface and end up at the correct implementation.

如何在 Prolog 中执行此操作?

How do I do it in Prolog?

示例代码:

robin.pl

:- module(robin,
          [
           robin/0
          ,toolshed/1
          ]).

:- use_module(library('helper.pl')).

robin :- helper(friar_tuck,help).

toolshed('a katana made by mastersmith Masamune').
toolshed('an ancient shovel with a sharpened blade').
toolshed('an Uzi 9mm with Norinco markings').

arthur.pl

:- module(arthur,
          [
           arthur/0
          ,toolshed/1
          ]).

:- use_module(library('helper.pl')).

arthur :- helper(merlin,help).

toolshed('a slightly musty grimoire').
toolshed('a jar of mandragore').
toolshed('a fresh toadstool').

helper.pl

:- module(helper,
          [
          helper/2
          ]).

helper(friar_tuck,help) :-
   format("I will help you rout the Sheriff of Nottingham's men!~n"),
   setof(X,toolshed(X),Tools),
   format("I found these tools: ~q~n",[Tools]),
   format("Have at them!~n").

helper(merlin,help) :-
   format("I will help you rout Mordred's army!~n"),
   setof(X,toolshed(X),Tools),
   format("I found these tools: ~q~n",[Tools]),
   format("Have at them!~n").

将它们放入导演testing:

testing
├── arthur.pl
├── helper.pl
└── robin.pl

启动swipl,设置库搜索路径并加载arthur.pl:

Launch swipl, set the library search path and load arthur.pl:

?- assertz(file_search_path(library,'/home/me/testing')).
true.

?- use_module(library('arthur.pl')).
true.

?- arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!
true.

所以这是有效的.toolshed/1 由模块 arthur 导出,并且模块 helper 可见(并且可调用未限定)即使 helper <强>不导入 arthur.pl(不太确定它是如何工作的,也许属于当前堆栈上的谓词的所有模块的导出谓词是可见的并且不可访问?).

So this works. toolshed/1 is exported by module arthur and visible (and callable unqalified) by module helper even though helper does not import arthur.pl (not quite sure how that works, mabye the exported predicates of all modules belonging to predicates currently on the stack are visible and accessible unqalified?).

但我也无法加载robin.pl:

?- use_module(library('robin.pl')).
ERROR: import/1: No permission to import robin:toolshed/1 into user (already imported from arthur)
true.

好的,这并不奇怪.但是我怎样才能得到我想要的结果呢?我想看这个:

Ok, this is not surprising. But how do I get the result I want? I want to see this:

?- use_module(library('robin.pl')).
true.

?- robin.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!
true.

推荐答案

一个有趣的问题.遵循完全可移植的 Logtalk 解决方案(对可移植性进行了微小的更改,并避免了对讨厌的 double_quotes 标志的依赖;format/2 是事实上的标准谓词,它接受第一个参数,但谓词可用的方式取决于 Prolog 系统,并且不需要用这些细节来混淆代码):

An interesting problem. Follows a fully portable Logtalk solution (with minor changes for portability and avoiding dependencies on the pesky double_quotes flag; format/2 is a de facto standard predicate that accepts an atom in the first argument but the way the predicate is made available depends on the Prolog system and there's no need of cluttering the code with those details):

:- protocol(toolshed).

    :- public(toolshed/1).

:- end_protocol.


:- category(helper).

    :- private(helper/2).

    helper(friar_tuck, help) :-
        write('I will help you rout the Sheriff of Nottingham\'s men!\n'),
        setof(X, ::toolshed(X), Tools),
        write('I found these tools: '), writeq(Tools), nl,
        write('Have at them!\n').

    helper(merlin, help) :-
        write('I will help you rout Mordred\'s army!\n'),
        setof(X, ::toolshed(X), Tools),
        write('I found these tools: '), writeq(Tools), nl,
        write('Have at them!\n').

:- end_category.


:- object(robin,
    implements(toolshed),
    imports(helper)).

    :- public(robin_hood/0).

    robin_hood :-
        ^^helper(friar_tuck, help).

    toolshed('a katana made by mastersmith Masamune').
    toolshed('an ancient shovel with a sharpened blade').
    toolshed('an Uzi 9mm with Norinco markings').

:- end_object.


:- object(arthur,
    implements(toolshed),
    imports(helper)).

    :- public(arthur/0).

    arthur :-
        ^^helper(merlin, help).

    toolshed('a slightly musty grimoire').
    toolshed('a jar of mandragore').
    toolshed('a fresh toadstool').

:- end_object.

然后(假设上面的代码保存在一个 dh.lgt 文件中):

Then (assuming the above code saved in a dh.lgt file):

$ swilgt
...

?- {dh}.
...
true.

?- robin::robin_hood.
I will help you rout the Sheriff of Nottingham's men!
I found these tools: ['a katana made by mastersmith Masamune','an Uzi 9mm with Norinco markings','an ancient shovel with a sharpened blade']
Have at them!~n
true.

?- arthur::arthur.
I will help you rout Mordred's army!
I found these tools: ['a fresh toadstool','a jar of mandragore','a slightly musty grimoire']
Have at them!~n
true.

您不仅可以使用 Logtalk,还可以使用其所有支持的后端 Prolog 系统运行此解决方案.

You can run this solution not only with Logtalk but with all its supported backend Prolog systems.

如果您不希望 toolshed/1 谓词是公开的,您可以更改对象打开指令,使谓词成为受保护的或私有的.例如:

If you don't want the toolshed/1 predicate to be public, you can change the object opening directives to make the predicate either protected or private. For example:

:- object(robin,
    implements(private::toolshed),
    imports(helper)).

这会给你:

?- arthur::toolshed(T).
!     Permission error: access private_predicate toolshed/1
!       in goal: arthur::toolshed(A)

您也可以更改协议以将谓词设为私有,但这并不符合习惯.

You could also change the protocol to make the predicate private there but that would not be idiomatic.

这篇关于跨模块的“接口"调用 SWI-Prolog的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆