Logtalk:meta :: map,lambda表达式和访问私有方法

时间:2012-02-27 06:21:23

标签: logtalk

我认为这是与范围相关的问题。如果我对我的对象有这样的规则:

:- 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的这种用法将事实放在正确的命名空间中(在新创建的实例上)。但是,如果我诙谐并用这个lambda表达式替换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 个答案:

答案 0 :(得分:2)

让我首先使用上面的代码片段,其中对象name实例化。在此过程中,您将name作为自己的类。什么都没有错。在支持元类的语言中,例如Smalltalk和Logtalk,使类成为自己的元类是避免无限回归的经典方法。例如,参见关于元类的维基百科条目(http://en.wikipedia.org/wiki/Metaclass)。另请参阅Logtalk分发中的“反射”示例。通过使对象name实例化自身,它既可以扮演实例的角色(当实例化对象时),也可以扮演类的角色(因为它是由对象实例化的)。如果将name定义为独立对象,即与其他对象无关的对象,则将其编译为原型。

现在回答你的问题。在Logtalk中,在 sender 的上下文中调用元谓词(例如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开发版本中。感谢您提醒我注意这个错误。