2

これはスコープ関連の問題だと思います。オブジェクトに次のようなルールがある場合:

:- public(new/2).
:- mode(new(+list, -object_identifier), one).
new(Args, Instance) :-
    self(Self),
    create_object(Instance, [instantiates(Self)], [], []),
    Instance::process_arguments(Args).

私がこのダンスをするなら、これはうまくいくと思います:

:- object(name, instantiates(name)).

なぜこれが必要なのか完全には理解していませんが、それが私の実際の問題に関連しているのではないかと思います。つまり、オブジェクトに標準のPrologループがある場合、次のようになります。

process_arguments([Arg|Args]) :- process_arg(Arg), process_arguments(Args).
process_arguments([]).

process_arg(Arg) :- ::asserta(something(Arg)).

::assertaこの使用により、ファクトが(新しく作成されたインスタンスの)正しい名前空間に配置されることがわかりました。ただし、機知に富み、の本体process_arguments/1をこのラムダ式に置き換えると、次のようになります。

process_arguments(Args) :- meta::map([Arg]>>process_arg(Arg), Args).

次に、ファクトが親クラスに追加され、すべてのインスタンスで共有されることになります。これに置き換えると:

process_arguments(Args) :-
    self(Self),
    meta::map([Arg]>>(Self::process_arg(Arg)), Args).

それでうまくいきますが、したくないときは公のルールを作らprocess_arg/1なければなりません。私は何が欠けていますか?

4

1 に答える 1

1

nameまず、オブジェクトがそれ自体をインスタンス化する上記のコードスニペットから始めましょう。これを行うことでname、独自のクラスを作成します。どこに問題はありません。SmalltalkやLogtalkなどのメタクラスをサポートする言語では、クラスを独自のメタクラスにすることは、無限の回帰を回避するための古典的な方法です。たとえば、メタクラスに関するWikipediaのエントリ(http://en.wikipedia.org/wiki/Metaclass)を参照してください。Logtalkディストリビューションの「リフレクション」の例も参照してください。オブジェクトをnameそれ自体でインスタンス化することにより、インスタンスの役割(オブジェクトをインスタンス化するとき)とクラスの役割(オブジェクトによってインスタンス化されるとき)の両方を果たします。nameスタンドアロンオブジェクト、つまり他のオブジェクトとは関係のないオブジェクトとして定義した場合、プロトタイプとしてコンパイルされます。

今あなたの質問に。Logtalkでは、メタ述語(などmeta::map/2)は送信者のコンテキストで呼び出されます。process_arguments/1述語がで定義されている場合name、実行コンテキスト(selfの値を含む)はになりますname。したがって、の句something/1はでアサートされnameます。(組み込みメソッドを使用することによる)回避策は期待どおりに機能しますが、パブリック述語self/1を宣言する必要があります。process_arg/1これは、安定したLogtalkバージョンのバグです。これは、process_arg/1述語が保護されているかプライベートであるかを宣言することによっても機能するはずです(送信者がそうnameであり、述語が送信者で宣言されているため)。例えば:

:- object(name,
    instantiates(name)).

    :- public(new/2).
    :- mode(new(+list, -object_identifier), one).
    new(Args, Instance) :-
        self(Self),
        create_object(Instance, [instantiates(Self)], [set_logtalk_flag(dynamic_declarations, allow)], []),
        meta::map({Instance}/[Arg]>>(Instance::process_arg(Arg)), Args).

    :- private(process_arg/1).
    process_arg(Arg) :-
        ::asserta(something(Arg)).

:- end_object.

今週後半に、公開されているLogtalk開発バージョンにバグ修正をプッシュします。このバグに注意を向けてくれてありがとう。

于 2012-02-27T22:55:20.967 に答える