3

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

* は 2 つの関係の合成です。たとえば、後継者に関して追加を定義するために使用できます。後継者は次の関係になります。

 ?- F = \A^B^(B is A+1), call(F, 2, R).
 R = 3        /* 3 = 2+1 */

追加は次のように行うことができます (SWI-Prolog):

 ?- F = \A^B^(B is A+1), rec(F, 8, G), call(G, 3, R).
 R = 11       /* 11 = 3+8 */

ここで、rec/3 の節の前に、次のように meta_predicate 宣言を追加するとします。

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

  ?- F = \A^B^(B is A+1), rec(F, 8, G), call(G, 3, R).
  false

meta_predicate が存在する場合に機能するように、rec/3 とクエリの句を修正するにはどうすればよいですか?

さよなら

4

3 に答える 3

1

SWI メタ述語の宣言とモジュールは、Quintus、SICStus、および YAP のものと似ています。これらのシステムの基本的な前提は、すべての情報が を使用して宣言されたメタ引数を介して渡されること(:)/2です。隠された状態やコンテキストはありません。一般的なケース (単純なインスタンス化された引数) の場合、メタ述語宣言は、プログラマーからの明示的な修飾の負担を軽減するのに十分です。

ただし、現在のようなより複雑な状況では、明示的な修飾が​​追加されることを確認する必要があります。(:)/2さらに、それに応じてプレフィックスを「逆参照」する必要があります。SWIには、次のものがありますstrip_module/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).

がどこにでもインポートされると仮定すると、library(lambda)これは 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).

むしろ、補助引数の数ごとに1つのバージョン、したがって

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

名前はもっと良いかもしれませんが、オペレーターはそうしません。

于 2014-06-25T22:58:00.063 に答える