【问题标题】:Logtalk: meta::map, lambda expression and access to private methodLogtalk:meta::map、lambda 表达式和对私有方法的访问
【发布时间】:2012-02-27 06:21:22
【问题描述】:

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

:- 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 设为公共规则,而我不想这样做。我错过了什么?

【问题讨论】:

    标签: logtalk


    【解决方案1】:

    让我首先从上面的代码 sn-p 开始,其中对象 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 谓词受保护或私有(因为 sendername 并且谓词在 sender )。例如:

    :- 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 开发版本中。感谢您引起我对这个错误的关注。

    【讨论】:

    • 将错误修复推送到公开可用的 Logtalk 开发版本 (r6516)。
    • 该错误修复包含在今天早些时候发布的新 Logtalk 稳定版本 2.44.0 中。
    • “Closure = {Instance}/[Arg]>>(Instance::process_arg(Arg)), meta::map(Closure, Args)”也可以吗?我在源代码中看到您展开 meta::map/2。
    • @j4nbur53 使用库元编译器时会编译 lambda 表达式。但由于变量Instance 仅在运行时已知,闭包::/2 本身不能编译为使用静态绑定。当然,按照您的建议写 Closure = {Instance}/[Arg]>>(Instance::process_arg(Arg)), meta::map(Closure, Args) 也可以。
    • @j4nbur53 对象可以是静态的或动态的。源文件可以定义两者。 “实例”是一个对象可以扮演的角色。参见logtalk.org/manuals/userman/objects.html#objects_kind 当在编译时知道消息发送调用的对象参数时,通常可以进行静态绑定(假设打开了optimize 标志)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 2011-07-02
    • 2016-06-20
    相关资源
    最近更新 更多