Logtalk: meta::map, лямбда-выражение и доступ к приватному методу

Я думаю, что это проблема, связанная с объемом. Если у меня есть правило для моего объекта, как это:

:- 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 публичное правило, когда я предпочел бы нет. Что мне не хватает?

1 ответ

Решение

Позвольте мне начать с вашего фрагмента кода выше, где объект name создает себя. Делая это, вы делаете name свой собственный класс. В этом нет ничего плохого. В языках, которые поддерживают мета-классы, таких как Smalltalk и Logtalk, создание класса своим собственным мета-классом является классическим способом избежать бесконечной регрессии. См., Например, статью Википедии о мета-классах ( 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 позже на этой неделе. Спасибо за внимание к этой ошибке.

Другие вопросы по тегам