如果正则表达式是方法,则它们对应于哪个类?

时间:2019-06-27 18:01:08

标签: oop perl6

正则表达式实际上是方法:

say rx/foo/.^mro # ((Regex) (Method) (Routine) (Block) (Code) (Any) (Mu))

在这种情况下,这意味着他们可以对自己采取行动,并且属于阶级的一部分。那班是什么?我的直觉是这是Match类,它们实际上是在$ /上作用(它们实际上是)。还有其他表达方式吗?

3 个答案:

答案 0 :(得分:8)

最终,所有正则表达式都希望收到类型为MatchMatch的某些子类的请求者。在Perl 6中,倡导者只是第一个论点,在任何其他方面都不特殊。

在软件包中用ruletokenregex声明的那些正则表达式将作为该软件包中的方法安装。通常,它们是在grammar中声明的,它只不过是其默认父级为class而不是Grammar的{​​{1}}。 AnyGrammar的子类型。

Match

因此很自然地将它们视为方法,但是主体使用不同的语言编写。实际上,这正是它们的本质。

要知道匿名正则表达式如何成为方法要困难一点,因为它们不会安装在任何类型的方法表中。但是,如果我们要写:

grammar G {}.^mro.say # ((G) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))

然后我们看到,即使此方法实际上未安装在类class C { method foo() { 42 } } my $m = anon method () { self.foo } say C.$m() 上,也可以通过self解析该请求者的符号。匿名正则表达式也是如此。之所以如此重要,是因为C<ident><.ws>和朋友之类的断言实际上已编译为方法调用。

因此,匿名正则表达式是方法,因此将其第一个参数视为倡导者,才可以解决在<?before foo>上声明的各种内置规则。

答案 1 :(得分:7)

方法不必与任何类相对应:

my method bar () { say self, '!' }

bar 'Hello World'; # Hello World!


my regex baz { :ignorecase 'hello world' }

'Hello World' ~~ /<baz>/;
'Hello World' ~~ &baz;
&baz.ACCEPTS('Hello World'); # same as previous line

# baz 'Hello World';

默认情况下,通过扩展名,正则表达式与它们在其中声明的任何类都具有has关系。

class Foo {
        method bar () { say self, '!' }
  # has method bar () { say self, '!' }

        regex  baz    { :ignorecase 'hello world' }
  # has regex  baz () { :ignorecase 'hello world' }
}

正则表达式的确需要满足一些要求,无论其要求是什么。

通过将其作为子例程运行,它会告诉您第一个:

my regex baz { :ignorecase 'hello world' }

baz 'Hello World';
No such method '!cursor_start' for invocant of type 'Str'
  in regex baz at <unknown file> line 1
  in block <unit> at <unknown file> line 1

通常,在用grammar声明的类中声明正则表达式。

grammar Foo {
}

say Foo.^mro;
# ((Foo) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))

因此,在这种情况下,可能需要GrammarMatchCapture来满足要求。

它也可能来自与之融为一体的角色。

say Foo.^roles.map(*.^name);
# (NQPMatchRole)

甚至更有理由相信它是MatchCapture

my regex baz {
    ^
    { say 'baz was called on: ', self.^name }
}
&baz.ACCEPTS(''); # baz was called on: Match
my regex baz ( $s ) {
    :ignorecase
    "$s"
}
baz Match.new(orig => 'Hello World'), 'hello';
# 「Hello」

我看不出有人在普通班级还是不能这样做。


请注意,$/只是一个变量。因此,说将其传递给正则表达式是对情况的误解。

my regex baz ( $/ ) {
    :ignorecase
    "$/"
}
'Hello World' ~~ /<baz('hello')>/;
# 「Hello」
#  baz => 「Hello」

准确地说,当从另一个内部调用正则表达式时,当前的$/用作方法/正则表达式的调用者。
(我不完全确定这是否会发生。)

因此,前面的示例将像这样:

'Hello World' ~~ /{ $/.&baz('hello') }/;

答案 2 :(得分:3)

这种解释结合了我认为Brad ++和Jonathan ++刚刚教给我的知识,以为我已经知道的知识以及进一步挖掘后发现的知识。

(我的最初目标是直接解释Brad神秘的No such method '!cursor_start'信息。我现在已经失败了,只是提交了a bug report,但这就是我的最终目的。)

方法

方法被设计为在类中自然工作。实际上,没有作用域声明符的方法声明假定has -并且has声明属于一个类:

method bar {} # Useless declaration of a has-scoped method in mainline

但是实际上方法也可以很好地工作:

  • sub s(即完全表现为面向对象的方法);或

  • prototype-based programming的方法(即,面向对象,但没有类)。

真正使方法成为方法的是它们是带有"invocant"的例程。倡导者是特殊的状态优先参数,

  • 如果未显式声明,则隐式插入方法的signature中。如果在类内声明了方法,则类型约束为该类,否则为Mu
        class foo { my method bar {} .signature .say } # (foo: *%_)
                    my method bar {} .signature .say   # (Mu: *%_)
  • 是必需的位置。因此:
        my method bar {}
        bar # Too few positionals passed; expected 1 argument but got 0
  • 总是别名为self。因此:
        my method bar { say self }
        bar 42 # 42
    有时通过将其指定为签名中的第一个参数并在其后加上冒号(:)来明确声明。因此:
        my method bar (Int \baz:) { say baz } 
        say &bar.signature; # (Int \baz: *%_)
        bar 42;             # 42
        bar 'string';       # Type check failed in binding to parameter 'baz'

正则表达式

正则表达式是仅以激进者为视角的方法,它采用/期望匹配对象作为激进者。

正则表达式通常在三种不同的情况下被调用:

  • 直接使用。例如my regex foo { . }; say 'a' ~~ &foo; # 「a」(或仅say 'a' ~~ / . /; # 「a」,但为了简化说明,我将仅介绍基本相同的命名示例)。这将转换为say &foo.ACCEPTS: 'a'。这就是implemented by this code in Rakudo。如您所见,这将以正则表达式foo-which runs this code而不使用Match.'!cursor_init'(...)来调用正则表达式:build。结果是foo得到了一个新的Match对象作为其发起人。

  • 通过Grammar类的.parse方法。 The .parse method创建语法的新实例,然后将顶部的“规则”称为(rule / token / regex / method)上的新语法对象。请注意,GrammarMatch的子类;因此,就像第一种情况一样,正在将规则/正则表达式传递为一个空匹配对象。如果最高规则匹配,则对.parse的调用将返回新的语法/匹配对象。 (否则它将返回Nil。)

  • 通过上述方式之一。语法中的最高规则通常包含对较低级别的规则/令牌/正则表达式/方法的调用。同样,独立规则/正则表达式可能包含对其他规则/正则表达式的调用。每个此类调用将涉及创建另一个新的语法/匹配对象,该对象成为嵌套调用的发起者。如果嵌套调用匹配并且是捕获调用,则新的语法/匹配对象将添加到更高级别的语法/匹配对象。