gpt4 book ai didi

raku - 为什么向类型添加方法与在 perl6 中添加子或运算符不同?

转载 作者:行者123 更新时间:2023-12-03 14:51:02 25 4
gpt4 key购买 nike

使 subs/procedures 可用于重用是模块的一个核心功能,我认为这是一种语言可以组合并因此在程序员时间上有效的基本方式:

如果你在你的模块中创建一个类型,我可以创建我自己的模块,添加一个对你的类型进行操作的子。我不必扩展你的模块来做到这一点。

# your module
class Foo {
has $.id;
has $.name;
}

# my module
sub foo-str(Foo:D $f) is export {
return "[{$f.id}-{$f.name}]"
}

# someone else using yours and mine together for profit
my $f = Foo.new(:id(1234), :name("brclge"));
say foo-str($f);


Overloading operators for a class 中所见模块的这种可组合性对操作符同样有效,这对我来说是有道理的,因为无论如何,操作符只是 subs 的某种语法糖(至少在我的脑海中)。请注意,此类运算符的定义不会导致现有代码的行为发生任何令人惊讶的变化,您需要将其显式导入代码以访问它,就像上面的 sub 一样。

鉴于此,我发现我们没有类似的方法机制很奇怪,例如参见讨论在 How do you add a method to an existing class in Perl 6? ,特别是因为 perl6 是这样一种方法快乐的语言。如果我想扩展现有类型的使用,我想以与编写原始模块相同的风格来做。如果 Int 上有一个 .is-prime,我必须可以添加一个.is-semi-prime 也是,对吧?

我阅读了上面链接中的讨论,但不太认同“远距离 Action ”的说法:这与我从模块中导出另一个多子组件有何不同?例如,使这个词法变化(Trait + impl ... for)的生锈方式对我来说似乎很卫生,并且非常符合上面的操作符方法。

比技术性更有趣(至少对我而言)是语言设计的问题:为现有名词(类型)提供新动词(子、运算符、方法)的能力不是像 perl6 这样的语言的核心设计目标吗?如果是,为什么它会以不同的方式对待方法?如果它确实出于充分的理由区别对待它们,这是否意味着我们将许多不可组合的方法用作名词,而我们应该使用 subs 代替?

最佳答案

从语言设计的角度来看,这一切都归结为一个简单的问题:我们在说哪种语言?在 Perl 6 中,这是一个我们总是试图弄清楚的问题。

Perl 6 中的当前语言的概念完全是根据词法范围定义的。子声明是词法范围的。当我们从模块导入符号时,包括额外的 multi候选人,那些是词法范围的。当我们执行语言调整时——比如引入新的运算符——这些是词法范围的。我们当前语言中的动词 - 即子程序调用 - 是具有词法定义的动词。 (运算符只是 sub 调用,具有更有趣的解析。)由于词法作用域在编译期结束时关闭,因此编译器具有当前语言的完整 View 。这就是为什么 sub 调用不存在的 sub s,或对未声明变量的引用,在编译时被检测和报告,以及一些基本的编译时类型检查; future 的 Perl 6 版本可能会扩展可预期的编译时检查集。当前的语言是静态的、早期绑定(bind)的 Perl 6 的一部分。

相比之下,方法调用是要在目标对象的语言中解释的动词。这是 Perl 6 中动态的、后期绑定(bind)的部分。 虽然最直接的结果是在 OO 实现中的各种形式中发现的典型多态性,但由于元编程,甚至连动词的解释方式都被提升了抢夺。例如,monitor将在解释动词时获取锁并在之后释放它。其他对象可能是 constructed based on things other than Perl 6 code ,因此动词的解释并不意味着调用编写为 Perl 6 方法的代码。或者代码可能在网络上的某个地方。谁知道?好吧,当然不是调用者,这就是后期绑定(bind)的重点、力量和风险。

Perl 6 对“我想在我当前的语言中扩展我可以与这个对象一起使用的动词范围”的回答非常简单:使用与扩展当前语言相关的语言功能!甚至还有一种特殊的语法,$obj.&foo , 允许动词 foo以当前语言定义 - 通过编写 sub - 然后就好像它是对象上的方法一样被调用。然而,细微的句法区别让读者 - 以及编译器 - 清楚发生了什么,以及哪种语言正在定义该动词。

通过使用 augment可以扩展由某种类型的对象定义的语言。然而,它很少是最好的做事方式,因为它会产生全局影响,并且还会分散对象语言的定义。

我们在编程中所做的大部分工作都是关于构建语言。我的意思不是新语法;我们的大多数新语言——即使是像 Perl 6 这样对变异开放的语言——只是使用标准语言特性定义的名词和动词。然而,在任何非平凡的程序中,我们不可能同时记住每种语言的每一个细节。当我去餐厅点炸肉排时,我不知道订单将如何运送到厨房,厨房是什么样子,炸肉排是按要求敲打、裹上面包屑和烹制的,还是直接从准备好的炸肉排的(希望不会太陈旧)缓存。厨房和我有足够的共同意义来让正确的事情发生,但我不知道他们会如何准确地回应我的要求,他们也不需要知道在此期间我会做什么。这种想法被 OO 本身承认——至少当我们完全接受它时——并且在更大范围内被诸如领域驱动设计中的有界上下文之类的概念所承认。

总而言之,Perl 6 试图帮助我们保持我们的语言直截了当:了解我们当前语言中的内容,以及我们仅以有限的理解表达的内容。这种区别由 sub 编码/method区别,事实证明,这也是悬挂静态/动态区别的明智之选。

关于raku - 为什么向类型添加方法与在 perl6 中添加子或运算符不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56011589/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com