Perl 6 对象如何找到可能位于父类或角色中的多重方法?

2024-02-08

考虑这个例子,其中子类有一个没有签名的 multi 方法和一个带有 slurpy 参数的方法:

class Foo {
    multi method do-it { put "Default" }
    multi method do-it ( Int $n ) { put "Int method" }
    multi method do-it ( Str $s ) { put "Str method" }
    multi method do-it ( Rat $r ) { put "Rat method" }
    }

class Bar is Foo {
    multi method do-it { put "Bar method" }
    multi method do-it (*@a) { put "Bar slurpy method" }
    }

Foo.new.do-it: 1;
Foo.new.do-it: 'Perl 6';
Foo.new.do-it: <1/137>;
Foo.new.do-it;

put '-' x 10;

Bar.new.do-it: 1;
Bar.new.do-it: 'Perl 6';
Bar.new.do-it: <1/137>;
Bar.new.do-it: 5+3i;
Bar.new.do-it;

方法查找的结构如何?我更多地寻找一种方法来解释它,特别是不抱怨它。

Int method
Str method
Rat method
Default
----------
Int method
Str method
Rat method
Bar slurpy method
Bar method

有电话打给Bar's do-it with 1例如。一些理智的人可能会认为它在寻找匹配的签名Bar首先,那个粘糊糊的东西永远不会让任何东西过去。然而,该调用在继承链中找到了正确的多重。

Does Bar已经知道所有签名了吗?它是否会进行搜索,或者所有这些内容在编写时都已经解决了吗?

并且,有没有办法在运行时找出哪个类提供了该方法?也许需要打电话询问如何?当我有一个错误指定的多重并且正在其他地方处理时,这将是一个方便的调试工具。


对于多次调度要记住的关键是它会发生after子或方法解析已发生。因此,所有多重调度实际上是一个两步过程。这两个步骤也是相互独立的。

当写这样的东西时:

multi sub foo($x) { }
multi sub foo($x, $y) { }

编译器会生成一个:

proto sub foo(|) {*}

也就是说,除非你写了一个proto自己分。这proto是实际安装到 lexpad 中的内容; Amultisub 永远不会直接安装到 lexpad 中,而是安装到 的候选列表中proto.

因此,当调用multi子,流程为:

  1. 使用词法查找查找要调用的子程序,解析为proto
  2. 致电proto,选择最好的multi候选人并称之为

当有multi嵌套范围内的候选人,proto来自外部作用域的将被克隆并安装到内部作用域中,并将候选者添加到克隆中。

多种方法都会发生非常相似的过程,除了:

  • 多种方法只是存储在待办事项列表中,直到结束}类、角色或语法的
  • A proto可以由角色或类提供,因此用以下方式组合角色multi候选人也只需将他们添加到待办事项列表中
  • 最后,如果有多种方法没有proto,但是父类有这样一个proto,将被克隆;否则为空proto将被制作

这意味着对多方法的调用是:

  1. 使用通常的方法分派算法查找方法(仅使用 C3 方法解析顺序搜索类),该算法解析为proto
  2. 致电proto,选择最好的multi候选人并称之为

完全相同的排序和选择算法用于多子方法和多方法。就多重分派算法而言,调用者只是第一个参数。此外,Perl 6 多重分派算法并不比后面的参数更重视前面的参数,所以就像:

class A { }
class B is A { }
multi sub f(A, B) { }
multi sub f(B, A) { }

将被视为绑定,如果使用以下命令调用,则会给出不明确的调度错误f(B, B),定义也是如此:

class B { ... }
class A {
    multi method m(B) { }
}
class B is A {
    multi method m(A) { }
}

然后打电话B.m(B),因为多重发射器再次只看到类型元组(A, B) and (B, A).

多重调度本身就与狭隘性的概念有关。如果 C1 的至少一个参数的类型比 C2 中相同位置的参数窄,并且所有其他参数都相等(即不更窄,也不更宽),则候选 C1 比 C2 窄。如果反之亦然,则它更宽。否则,就被绑住了。一些例子:

(Int) is narrower than (Any)
(Int) is tied with (Num)
(Int) is tied with (Int)
(Int, Int) is narrower than (Any, Any)
(Any, Int) is narrower than (Any, Any)
(Int, Any) is narrower than (Any, Any)
(Int, Int) is narrower than (Int, Any)
(Int, Int) is narrower than (Any, Int)
(Int, Any) is tied with (Any, Int)
(Int, Int) is tied with (Int, Int)

多重匹配器构建候选者的有向图,其中只要 C1 比 C2 窄,就存在从 C1 到 C2 的边。然后,它找到所有没有传入边缘的候选者,并将其删除。这是第一组候选人。删除将产生一组没有传入边缘的新候选集,然后将其删除并成为第二组候选集。这种情况一直持续到从图中取出所有候选者为止,或者到达无法从图中取出任何内容的状态(这是一种非常罕见的情况,但这将作为循环性报告给程序员)。这个过程发生once,而不是每次调度,它会产生一组候选人。 (是的,这只是一种拓扑排序,但分组细节对于接下来的内容很重要。)

当呼叫发生时,系统会按顺序搜索组以查找匹配的候选者。如果同一组的两名候选人比赛,并且没有决胜局(命名参数,where条款或暗示where条款来自subset类型、解包或is default) 那么将会报告一个不明确的调度。如果搜索完所有组都没有找到结果,则调度失败。

还有一些关于数量的狭隘性考虑(必需参数击败可选参数或slurpy)和is rw(它比其他方面平等的候选人要窄,但没有is rw).

一旦发现一组中的一名或多名候选人匹配,就会考虑决胜局。其中包括命名参数的存在,where条款、解包,并在首场比赛获胜的基础上工作。

multi f($i where $i < 3) { } # C1
multi f($i where $i > 1) { } # C2
f(2) # C1 and C2 tied; C1 wins by textual ordering due to where

请注意,此文本顺序仅适用于平局决胜;就类型而言,源代码中候选者的顺序并不重要。 (命名参数也仅充当平局决胜者,有时会令人惊讶。)

最后,我要指出的是,虽然多重分派的结果始终与我描述的两步过程相匹配,但实际上会发生大量的运行时优化。虽然所有查找最初都完全按照描述进行解析,但结果会被放入调度缓存中,这比搜索拓扑排序提供的组提供的查找速度要快得多。它的安装方式可以完全绕过原型的调用,从而节省调用帧。您可以看到此行为的伪影,如果您--profile;自动生成的proto对于任何基于类型的调度(没有决胜局),与多个候选人相比,将收到少量的呼叫。如果您在中编写自定义逻辑,则这不适用proto, 当然。

除此之外,如果您在 MoarVM 上运行,动态优化器可以走得更远。它可以使用收集的和推断的类型信息来解析方法/子调度and多调度,将 2 步流程变成 0 步流程。小候选人也可以内联到调用者中(同样,探查器可以告诉您内联已经发生),这可以说将多分派变成了 -1 步骤过程。 :-)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Perl 6 对象如何找到可能位于父类或角色中的多重方法? 的相关文章

随机推荐

  • Mac X11 有 XTEST 扩展吗?

    所以我把一些 X 程序移到了 mac 上 然后我得到了 Error XTEST extension unavailable on null 来自 xdotool OS X X11 是否附带 XTEST 如果没有的话有办法添加吗 在终端中运行
  • WiX 自定义许可证文件:安装程序显示带有 < > 的链接

    我创建了一个带有自定义许可证文件的 WiX 3 5 设置 将其放入 wxs file
  • 无法安装 Facebook 6.4.2 软件包

    我正在尝试安装 facebook C sdkNuGet 控制台进入我的视窗电话 8 app NET框架4 0但它给出了一个错误 详细信息如下 PM gt Install Package Facebook Successfully insta
  • 从 itertools.cycle 中提取列表

    我有一堂课 其中包含itertools cycle我希望能够复制的实例 一种方法 我能想到的唯一方法 是提取初始可迭代对象 这是一个列表 并存储循环所在的位置 不幸的是 我无法获取用于创建循环实例的列表 似乎也没有明显的方法来做到这一点 i
  • 使用 Encode::encode 和“utf8”

    正如您可能知道的 在 Perl 中 utf8 意味着 Perl 对 UTF 8 的宽松理解 它允许在技术上不是 UTF 8 中有效代码点的字符 相比之下 UTF 8 或 utf 8 是 Perl 对 UTF 8 更严格的理解 它不允许无效的
  • 一条 SQL 语句中存在多个 WHERE 条件

    我无法使用很多WHERE条件 因为我确实需要结合8 Where单个语句中的条件 我当前的SQL SELECT FROM Table WHERE ID I want 某物像这样 SELECT FROM Table WHERE ID WHERE
  • 同时更新两个表的条​​件 SQL 语句

    我想一次更新两个表 下面的代码似乎工作正常 但是 在某些情况下 bidGroups 中没有条目 这意味着整个语句将失败 我怎样才能调整它 以便它更新第一位 watchedItems 并且如果watchedItems bidGroupID I
  • 错误:xcode-select:错误:工具“xcodebuild”需要 Xcode

    我在用Ionic 2 该应用程序构建了一个Androidapk在 Windows 上成功 我现在正在尝试构建它iOS在 OSX 上 当我跑步时 ionic build ios 我得到以下信息 任何建议表示赞赏 你需要配置xcode安装后 打
  • WCF REST 缓存 - 客户端和服务器端

    我写了一个 RESTful WCF 服务 合并 ETag 使标头过期 从浏览器使用它时 缓存效果很好 但是 当从 WCF 通道工厂或 NET Web 请求对象调用缓存时 缓存是如何工作的呢 因此 在我的网站在返回 304 未修改响应时调用
  • 之间有什么区别?

    当我使用
  • 使用 mongoimport 导入超过 1 个 json 文件

    我是新来的mongodb并想了解如何导入json文件从一台服务器传输到另一台服务器 我尝试了以下命令mongoimport d test c bik check json它对我来说效果很好 现在我想知道什么时候有多个json我如何一次性导入
  • 页面加载时 Twitter 引导程序进度条动画

    我有一个带有几个引导进度条的页面 最初设置它们的值效果很好 虽然我希望进度条在用户打开页面时动画 转换到其特定状态 当你点击其中一个栏时 这个 JS 工作正常 我在酒吧的 onload 事件中需要类似的东西 但 onload 事件不适用于
  • 无法让社交媒体共享按钮在内联列表中排列

    在我的一生中 我无法让这些社交媒体分享按钮与我的内嵌列表对齐 我差点就拥有了它vertical align top on the li 但 Chrome 不喜欢这样 页面可以在这里看到 http 206 72 114 49 sharelin
  • 在缓存中找不到元素 - 也许页面自从在 Selenium Ruby Web 驱动程序中查找后已发生更改?

    我正在尝试编写一个爬虫 它可以从加载的页面中爬取所有链接 并在某个文件 例如 XML 或 txt 中记录所有请求和响应标头以及响应正文 我正在新浏览器窗口中打开第一个加载页面的所有链接 因此不会出现此错误 Element not found
  • 嵌入共享库的绝对路径

    使用供应商提供的交叉编译工具链 显然是 OpenEmbedded 衍生品 我无法嵌入第三方 开源 内部编译 库的绝对路径 使用以下 gcc 命令行 arm linux gcc test connect send o gprs connect
  • VBA计算文件内容的MD5哈希值

    我需要一个 VBA 例程来计算文件内容的 MD5 哈希值 我找到了一些例子 例如 here https stackoverflow com questions 2826302 how to get the md5 hex hash for
  • 随机 2D 坐标生成

    我需要生成2D随机坐标并找到距一个中心位置的距离 import numpy as np import matplotlib pyplot as plt coords np random random integers 0 50 10 pri
  • 快速搜索高斯核中最大值的坐标

    我有一个简单的代码 可以使用以下命令生成 2D 高斯内核scipy stats gaussian kde http docs scipy org doc scipy 0 13 0 reference generated scipy stat
  • 在一个 ASP.NET MVC 5 解决方案中拥有单独的项目

    我希望在一个 ASP NET 解决方案中拥有许多项目 例如 20 个 所有项目都有自己的数据库 模型 视图和控制器 你能告诉我该怎么做吗 网址又会怎样呢 如果解决方案中有一个项目 则如下所示 本地主机 12345 控制器 视图 当项目较多时
  • Perl 6 对象如何找到可能位于父类或角色中的多重方法?

    考虑这个例子 其中子类有一个没有签名的 multi 方法和一个带有 slurpy 参数的方法 class Foo multi method do it put Default multi method do it Int n put Int