Logtalk: meta :: map, лямбда-выражение и доступ к приватному методу - PullRequest
3 голосов
/ 27 февраля 2012

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

:- 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 Ответ

2 голосов
/ 28 февраля 2012

Позвольте мне начать с приведенного выше фрагмента кода, в котором объект name создается. При этом вы делаете name своим собственным классом. В этом нет ничего плохого. В языках, которые поддерживают мета-классы, таких как Smalltalk и Logtalk, превращение класса в собственный мета-класс является классическим способом избежать бесконечной регрессии. См., Например, статью в Википедии о мета-классах (http://en.wikipedia.org/wiki/Metaclass).. См. Также пример «отражения» в дистрибутиве Logtalk. Создавая экземпляр объекта name, он играет роль экземпляра (как он создает объект) и роль класса (как он создается объектом). Если вы определили name как отдельный объект, то есть объект, не имеющий отношения к другим объектам, он будет скомпилирован как прототип .

Теперь к вашему вопросу. В Logtalk мета-предикаты (такие как meta::map/2) вызываются в контексте sender . Если предикат 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 позже на этой неделе. Спасибо за внимание к этой ошибке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...