6

Prolog で統合と OO をどのように組み合わせるのだろうか。term オブジェクトにマルチメソッド ディスパッチを実装したいと思います。

用語オブジェクトと単純な用語がなければ、次のようにして、複数引数のインデックス作成から利益を得ることができます。

collide_with(asteroid(_), asteroid(_)) :- /* case 1 */
collide_with(asteroid(_), spaceship(_,_)) :- /* case 2 */
collide_with(spaceship(_,_), asteroid(_)) :- /* case 3 */
collide_with(spaceship(_,_), spaceship(_,_)) :- /* case 4 */

しかし、上記は正確なタイプの一致のみを提供します。

サブクラス タイプの一致が必要な場合はどうすればよいですか (excelsior、galaxy など、ケース 2、3、および 4 にも一致する必要がある宇宙船のサブクラスがさらに存在する可能性があります)。

統合とインデックス作成は引き続き使用できますか?

さよなら

PS: 例はここからのもので、Prolog ソリューションはありません:
https://en.wikipedia.org/wiki/Multiple_dispatch

4

3 に答える 3

1

CLOS では、複数のディスパッチに使用されるジェネリック関数はクラスにカプセル化されず、関数名ごとにグループ化されます。したがって、ここでの等価物は単純な Prolog ルールになります。さらに、複数の引数のインデックス付けを想定すると、ルール ヘッド内の引数は、複数のディスパッチを実行したい「型」に対して十分にインスタンス化されている必要があります。これにより、間違った選択ポイントがなくても正しいルールが毎回選択されるようになります。OPの例として:

collide_with(asteroid(_), asteroid(_)) :-
    ...
collide_with(asteroid(_), spaceship(_)) :-
    ...
collide_with(spaceship(_), asteroid(_)) :-
    ...
collide_with(spaceship(_), spaceship(_)) :-
    ...

Prolog で統合がどのように機能するかを考えると、基本的な小惑星と宇宙船の「タイプ」の特殊化が必要な場合、Daniel の提案に従って、複合用語を使用しasteroid/1spaceship/1「タイプ」と「サブ」を定義する実際のオブジェクトのラッパーとして使用できます。種類"。欠けているのは、Logtalk などに見られるように、単一のディスパッチを使用して正しいルールにリダイレクトする方法です。ダニエルは、可能な解決策として二重ディスパッチを使用する方法をすでに説明しました。別の方法として、次のようなパラメトリック オブジェクトを定義することもできます。

:- object(collide_with(_, _)).

    :- public(bump/0).
    bump :-
        % access the object parameters
        this(collide_with(Obj1, Obj2)),
        % wrap the object parameters
        wrap(Obj1, Wrapper1), wrap(Obj2, Wrapper2),
        % call the plain Prolog rules
        {collide_with(Wrapper1, Wrapper2)}. 

    wrap(Obj, Wrapper) :-
        wrap(Obj, Obj, Wrapper).

    wrap(Obj, Wrapper0, Wrapper) :-
        (   extends_object(Wrapper0, Parent) ->
            wrap(Obj, Parent, Wrapper)
        ;   Wrapper =.. [Wrapper0, Obj] 
        ).

:- end_object.

また、小惑星と宇宙船の階層を表すために必要なすべてのオブジェクトも用意します (ここでは、簡単にするために、クラス/インスタンスの代わりにプロトタイプを使用しています)。例えば:

:- object(spaceship).
    ...
:- end_object.

:- object(galaxy, extends(spaceship)).
    ...
:- end_object.

:- object(asteroid).
    ...
:- end_object.

:- object(ceres, extends(asteroid)).
    ...
:- end_object.

典型的な使用法は次のとおりです。

?- collide_with(ceres, galaxy)::bump.
...

述語の単純な Prolog ルールcollide_with/2は (ラップされた) オブジェクト識別子を受け取るため、2 つのオブジェクトがぶつかったときに必要な動作を実装するために必要な情報を要求するメッセージをそれらのオブジェクトに送信するのは簡単です。

collide_with/2パラメトリック オブジェクトは、この複数のディスパッチ ソリューションの実装の詳細を抽象化します。Daniel によって説明された二重ディスパッチ ソリューションに対する利点の 1 つは、衝突メッセージのオブジェクトの 1 つを選択する必要がないことです。欠点の 1 つはbump/0、計算をトリガーするために、コードの場所に追加のメッセージが必要なことです。

于 2016-01-27T16:22:34.320 に答える
0

次のファンキーなアイデアがありました。instof/2 のミラーである述語 isinst/2 があるとします。Xが小惑星であることを確認したい場合。私たちがする宇宙船:

 isinst(asteroid, X). /* checks whether X is an asteroid */
 isinst(spaceship, X). /* checks whether X is a spaceship */

したがって、Prolog コードは単純です。

 collide_with(X, Y) :- isinst(asteroid, X), isinst(asteroid, Y), /* case 1 */
 collide_with(X, Y) :- isinst(asteroid, X), isinst(spaceship, Y), /* case 2 */
 collide_with(X, Y) :- isinst(spaceship, X), isinst(asteroid, Y), /* case 3 */
 collide_with(X, Y) :- isinst(spaceship, X), isinst(spaceship, Y), /* case 4 */

ここで、Prolog システムが属性変数と、X{...} などの属性変数の読み取り可能な概念を提供すると仮定します。次に、次のように定義します。

 collide_with(X{isinst(asteroid)}, Y{isinst(asteroid)}) :- /* case 1 */
 collide_with(X{isinst(asteroid)}, Y{isinst(spaceship)}) :- /* case 2 */
 collide_with(X{isinst(spaceship)}, Y{isinst(asteroid)}) :- /* case 3 */
 collide_with(X{isinst(spaceship)}, Y{isinst(spaceship)}) :- /* case 4 */

属性変数は統合に直接役立つため、これによりコードがわずかに高速になる可能性があります。ボディで何かをチェックする必要があるわけではありません。

それがより良いインデックス作成にもつながるかどうかは、現時点ではまだ不明です。問題は、継承階層が実行時に変更される可能性があり、これがインデックスに影響を与え、再インデックスが必要になる可能性があることです。これは、クラスを final としてマークするなどして、継承階層がオープンワールドでないことを保証できる場合にも当てはまります。Prolog システムが動的であると見なされる場合、これも変化する可能性があります。

それに加えて、継承階層がオープンワールドではない場合、つまりサブクラスを列挙できる場合、インデックス作成に関するいくつかの明白なアイデアがあります。ここでの唯一の問題は、可能であれば、同じボディで異なるヘッドを効率的に共有することです。そうしないと、節が爆発的に増える可能性があります。

さよなら

PS: 属性変数はフックを延期する可能性があるため、本体チェックから属性変数に移行する場合、意味が少し変わります。

X と Y はインスタンス化されていないため、ボディ チェックを使用すると、collide_with(X,Y) が失敗し、属性変数を使用すると、collide_with(X,Y) が成功する可能性があります。

しかし、collide_with/2 の引数がインスタンス化された場合、結果は多かれ少なかれ同じになるはずです。

于 2016-01-28T18:30:26.230 に答える