Module 如何在存在元谓词声明的情况下编写rec/3?

Module 如何在存在元谓词声明的情况下编写rec/3?,module,prolog,swi-prolog,meta-predicate,Module,Prolog,Swi Prolog,Meta Predicate,我有下面的代码,在没有 元谓词声明。我定义了一个谓词 rec/3如下: :- use_module(library(lambda)). rec(F,1,F). rec(F,N,\A^B^(call(F,A,H),call(G,H,B))) :- N>1, M is N-1, rec(F,M,G). 谓词rec/3基本上实现了以下功能 高阶递归方程: F^1 = F F^N = F*F^(N-1) for N>1 其中*是两个关系的组成。它可以 例

我有下面的代码,在没有 元谓词声明。我定义了一个谓词 rec/3如下:

:- use_module(library(lambda)).

 rec(F,1,F).
 rec(F,N,\A^B^(call(F,A,H),call(G,H,B))) :- 
      N>1, M is N-1, rec(F,M,G).
谓词rec/3基本上实现了以下功能 高阶递归方程:

 F^1 = F
 F^N = F*F^(N-1)      for N>1
其中*是两个关系的组成。它可以 例如,可用于根据定义添加 继承人继任者将是以下关系:

 ?- F = \A^B^(B is A+1), call(F, 2, R).
 R = 3        /* 3 = 2+1 */
然后可以按如下方式进行添加(SWI Prolog):

现在,如果我添加一个meta_谓词声明,如下所示, 在rec/3条款之前:

 :- meta_predicate rec(2,?,2).
 rec(F,1,F).
 rec(F,N,\A^B^(call(F,A,H),call(G,H,B))) :- 
      N>1, M is N-1, rec(F,M,G).
事情不再有效(SWI Prolog):

如何修复rec/3的子句和查询so 它们在元谓词存在的情况下工作


再见

您的代码的Logtalk版本没有问题:

:- object(rec).

    :- public(rec/3).
    :- meta_predicate(rec(2,*,*)).
    rec(F, 1, F).
    rec(F, N, [A,B]>>(call(F,A,H),call(G,H,B))) :- 
        N > 1, M is N - 1,
        rec(F, M, G).

    :- public(local/2).
    local(A, B) :-
        B is A + 1.

:- end_object.
我得到:

$ swilgt
...
?- {rec}.
% [ /Users/pmoura/Desktop/lgtemp/stackoverflow/rec.lgt loaded ]
% (0 warnings)
true.

?- F = [A,B]>>(B is A+1), rec::rec(F, 8, G), logtalk<<call(G, 3, R).
F = [A, B]>> (B is A+1),
G = [_G88, _G91]>> (call([A, B]>> (B is A+1), _G88, _G99), call([_G108, _G111]>> (call([A, B]>> (B is A+1), _G108, _G119), call([_G128, _G131]>> (call(... >> ..., _G128, _G139), call(... >> ..., _G139, _G131)), _G119, _G111)), _G99, _G91)),
R = 11 ;
false.

?- F = [A,B]>>(rec::local(A,B)), rec::rec(F, 8, G), logtalk<<call(G, 3, R).
F = [A, B]>> (rec<<local(A, B)),
G = [_G2655, _G2658]>> (call([A, B]>> (rec<<local(A, B)), _G2655, _G2666), call([_G2675, _G2678]>> (call([A, B]>> (rec<<local(A, B)), _G2675, _G2686), call([_G2695, _G2698]>> (call(... >> ..., _G2695, _G2706), call(... >> ..., _G2706, _G2698)), _G2686, _G2678)), _G2666, _G2658)),
R = 11 ;
false.
$swilgt
...
?-{rec}。
%[/Users/pmoura/Desktop/lgtemp/stackoverflow/rec.lgt-load]
%(0个警告)
对。
?-F=[A,B]>>(B是A+1),rec::rec(F,8,G),logtalk(B是A+1),
G=[[U G88,[U G91]>>(调用([A,B]>>(B是A+1),[U G88,[U G99]),调用([U G108,[U G111]>>(调用([A,B]>>(B是A+1),[U G108,[U G119]),调用([U G128,[U G131]>)>(调用(…>>,[U G128,[U G139],[U G131]),[U G119,[U G111],[U G91]),
R=11;
错。
?-F=[A,B]>>(rec::local(A,B)),rec::rec(F,8,G),logtalk(rec(call([A,B]>>)(rec(call([A,B]>>)(rec(call(…>>),G2695,G2706),call(…>>,G2706,G2698)),G2686,G2678)),G2666,G2658,,
R=11;
错。
请注意
meta_谓词/1
指令的“修复”。除了lambda表达式语法转换为Logtalk语法外,
rec/3
谓词的代码是相同的。但是,在Logtalk的情况下,本例中
meta_谓词/1
指令是不需要的(正如
rec/3
谓词所做的只是将一个术语转换为一个新术语)并且仅用于文档目的。您可以注释掉它,然后仍然使用
rec::rec/3
谓词,从
用户(即从顶级解释器)或从客户端对象调用它


call/3
调用是在
logtalk
内置对象的上下文中进行的,只是为了解释logtalk lambda表达式(logtalk无意在Prolog顶级解释器中提供其本机lambda表达式支持)。

SWI元谓词声明和模块与之类似 在昆图斯、西克斯图斯和雅普,这些理论的基本假设 系统是指所有信息都通过声明的 元参数使用
(:)/2
。没有隐藏状态 对于常见情况(简单的实例化参数) 元谓词声明足以减轻 程序员的明确限定

然而,在像现在这样更复杂的情况下,你必须 确保添加明确的限定条件。此外,您需要 为确保相应地“取消引用”
(:)/2
前缀。在SWI中, 有
strip\u模块/3

?- strip_module(a:b:c:X,M,G).
X = G,
M = c.
假设定义如下:

rec(_, -1, local).
rec(_,  0, =).
rec(F, 1, F).

local(S0,S) :-
   S is S0+1.
现在必须这样写:

:- meta_predicate goal_qualified(:,-).
goal_qualified(G,G).

:- meta_predicate rec(2,+,2).
rec(_, -1, G) :-
    strip_module(G,_,VG),
    goal_qualified(local,VG).
rec(_, 0, G) :-
    strip_module(G,_,VG),
    goal_qualified(=,VG).
rec(F, 1, G) :-
    strip_module(G,_,F).
许多人喜欢手动添加模块前缀:

:- meta_predicate rec(2,+,2).
rec(_, -1, G) :-
    strip_module(G,_,mymodule:local).
...
如果我们只局限于SWI,从而牺牲 与SICStus或YAP的兼容性:

:- meta_predicate rec(2,+,2).
rec(_, -1, _:mymodule:local).
rec(_, 0, _:(=)).
rec(F, 1, _:F).
你问题中的规则

rec(F,N,\A^B^(call(F,A,H),call(G,H,B))) :- 
      N>1, M is N-1, rec(F,M,G).
因此翻译为:

rec(F, N, MG) :-
   N > 1, M is N - 1,
   strip_module(MG,_,VG),
   goal_qualified(\A^B^(call(F,A,H),call(G,H,B)),VG),
   rec(F, M, G).
假设在任何地方都可以导入,这可以在SWI中再次简化为:

rec(F, N, _:(\A^B^(call(F,A,H),call(G,H,B)) )) :-
   N > 1, M is N -1,
   rec(F, M, G).

我的结论 1mo:系统应为总是失败的条款生成警告,如:

| ?- [user].
% compiling user...
| :- meta_predicate p(0).
| p(1).
% compiled user in module user, 0 msec 2080 bytes
yes
| ?- p(X).
no
2do:也许最好使用以下辅助谓词:

:- meta_predicate cont_to(:,:).
cont_to(MGoal, MVar) :-
   strip_module(MVar, _, Var),
   (  nonvar(Var)
   -> throw(error(uninstantiation_error(Var),_))
   ;  true
   ),
   (  strip_module(MGoal,_,Goal),
      var(Goal)
   -> throw(error(instantiation_error,_))
   ;  true
   ),
   Var = MGoal.
用法。

rec(_, -1, MV) :-
   cont_to(local, MV).
或者更确切地说:每个辅助参数数对应一个版本,因此

:- meta_predicate cont0_to(0,0).
:- meta_predicate cont1_to(1,1).
:- meta_predicate cont2_to(2,2).
...

名称可能更好,但运营商不会这样做。

以下straigh forward解决方案(仅在SWI Prolog上测试,但在任何情况下都远未实现基于Logtalk的解决方案的广泛可移植性):

给出:

?- [mrec].
true.

?- use_module(library(lambda)).
true.

?- F = \A^B^(B is A+1), rec(F,10,G), call(G,0,R).
F = \A^B^ (B is A+1),
G = \_G56^_G59^ (call(user: \A^B^ (...is...), _G56, _G67), call(\_G75^_G78^ (call(..., ..., ...), call(..., ..., ...)), _G67, _G59)),
R = 10 .
不需要低水平的黑客(
meta_谓词/1
指令的动机之一是避免使用明确的限定)或要求误导性的a
meta_谓词/1
指令。在重新阅读帖子和评论后,我仍然想知道你为什么要强行写:

:-meta_谓词(rec(2,?,2))。


rec/2
的第一个参数是not,它将被用作一个闭包,元谓词将附加两个参数来构造一个目标以调用它。第三个参数是一个输出参数。在第一个参数中,“2”表示输入,但对于第三个参数,它表示输出!在这两种情况下,元谓词都没有进行任何元调用!元谓词指令中长期存在的元参数指示符的含义被破坏的最终结果是,用户在不查看元谓词的实际代码。

此“修复”在SWI或任何其他具有meta_谓词指令的系统中也是可能的…如果参数引用rec的本地定义,则该命令不起作用;而它稍后将在另一个模块中调用。@false我编辑了我的答案,以说明引用
rec
对象的本地定义的参数。不确定它是否回答了您r观察。让我们知道。这样你就可以从外部参考非常局部的
local/2
定义?这显然打破了模块的界限。你需要导出
rec/3
来调用它。但是现在可以直接调用
local/2
,顺便说一句:我没有投反对票,我仍然认为Logtalk是一个有趣的实验。没有错h要么是
rec/3
谓词,要么是查询。错误的是
meta\u谓词/1
指令。从未调用第三个参数(由
rec/3
谓词本身)。因此,第三个参数
:- meta_predicate cont0_to(0,0).
:- meta_predicate cont1_to(1,1).
:- meta_predicate cont2_to(2,2).
...
:- module(m, [rec/3]).

:- use_module(library(lambda)). 

:- meta_predicate(rec(:,?,-)). 

rec(F, 1, F). 
rec(F, N, \A^B^(call(F,A,H),call(G,H,B))) :- 
    N > 1, M is N -1, 
    rec(F, M, G). 
?- [mrec].
true.

?- use_module(library(lambda)).
true.

?- F = \A^B^(B is A+1), rec(F,10,G), call(G,0,R).
F = \A^B^ (B is A+1),
G = \_G56^_G59^ (call(user: \A^B^ (...is...), _G56, _G67), call(\_G75^_G78^ (call(..., ..., ...), call(..., ..., ...)), _G67, _G59)),
R = 10 .