Если регулярные выражения являются методами, то какому классу они соответствуют?

Регулярные выражения на самом деле являются методами:

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

В этом случае это означает, что они могут действовать на себя и являются частью класса. Каким будет этот класс? Я догадываюсь, что это класс Match, и что они фактически действуют на $ / (что они на самом деле). Есть ли другой способ сформулировать это?

4
задан jjmerelo 27 June 2019 в 18:01
поделиться

3 ответа

Метод не должен соответствовать никакому классу:

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';
<час>

методами по умолчанию, и следовательно regexes имеют has отношения с любым классом, которым они объявляются в.

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

        regex  baz    { :ignorecase 'hello world' }
  # has regex  baz () { :ignorecase 'hello world' }
}
<час>

А regex действительно нужны некоторые требования, выполненные тем, что это - invocant.

, просто выполнив его как подпрограмму, он говорит Вам первую:

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

Обычно regex объявляется в классе, объявленном с [1 111].

grammar Foo {
}

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

, Таким образом, требования, вероятно, выполняются [1 112], Match, или Capture в этом случае.

Это могло также быть от роли, которая составлена с ним.

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

существует еще больше причины полагать, что это Match, или Capture

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」

я не вижу оснований, кто-то не мог сделать этого самостоятельно в нормальном классе все же.

<час>

Примечание, что $/ просто переменная. Так высказывание его передается regex, неверное толкование ситуации.

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

Это было бы больше с точностью до, говорят, что при вызове regex изнутри другого, ток $/ используется в качестве invocant к method/regex.
(я не совсем уверен, что это на самом деле, что происходит.)

, Таким образом, предыдущим примером тогда был бы вид - подобных это:

'Hello World' ~~ /{ $/.&baz('hello') }/;
6
ответ дан Brad Gilbert 27 June 2019 в 18:01
поделиться
  • 1
    Я часто использую x|0 для преобразования вдвое больший по сравнению с интервалом; однако это, а также использующий ' ~ ' имеет штраф ограничения числами < 2^32. + " 2e15" не делает. – Aki Suihkonen 1 March 2013 в 06:36

В конечном счете все регулярные выражения ожидают получить инвокант типа Match или некоторый подкласс Match. В Perl 6 инвокант - это просто первый аргумент, и он не является чем-то особенным.

Те регулярные выражения, объявленные с помощью rule, token или regex внутри пакета, будут установлены как методы для этого пакета. Наиболее типично, они объявлены в grammar, который является не чем иным как class, чей родитель по умолчанию - Grammar, а не Any. Grammar является подтипом 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> и друзья фактически скомпилированы в вызовы методов.

Таким образом, анонимные регулярные выражения, являющиеся методами, и, таким образом, трактующие свой первый аргумент как инвокант, позволяют разрешать различные встроенные правила, объявленные в Match.

7
ответ дан Jonathan Worthington 27 June 2019 в 18:01
поделиться

Это объяснение объединяет то, что, как мне кажется, Брэд ++ и Джонатан ++ только что научили меня, с тем, что, как я думал, я уже знал, с тем, что я обнаружил, когда копал дальше.

(Моя первоначальная цель состояла в том, чтобы напрямую объяснить таинственное сообщение Брэда No such method '!cursor_start'. Я пока что потерпел неудачу и вместо этого только что подал отчет об ошибке , но вот что еще я закончил.)

Методы

Методы предназначены для естественной работы в классах. Действительно, объявление метода без объявления области действия предполагает has - и объявление has принадлежит внутри класса:

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

Но на самом деле методы также работают нормально, так как:

Что действительно делает методы методами, так это то, что они являются подпрограммами с «инвокантом» . Инвокант - это первый параметр специального состояния, который:

  • неявно вставляется в сигнатуру метода , если не объявлено явно. Если метод объявлен внутри класса, тогда этим типом является ограничение типа, в противном случае это 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'. Это, в свою очередь, реализовано этим кодом в Rakudo . Как видите, это вызывает регулярное выражение foo с инвокантом Match.'!cursor_init'(...) - , которое выполняет этот код без :build. В результате этого foo получает новый объект Match в качестве инвоканта.

  • Посредством метода .parse класса Grammar. Метод .parse создает новый экземпляр грамматики и затем вызывает верхнее «правило» (rule / token / regex / method) для этого нового объекта грамматики. Обратите внимание, что Grammar является подклассом Match; поэтому, как и в первом сценарии, правилу / регулярному выражению передается пока еще пустой объект соответствия. Если верхнее правило соответствует, новый объект грамматики / соответствия будет возвращен вызовом .parse. (В противном случае он вернет Nil.)

  • Одним из перечисленных выше способов. Верхнее правило в грамматике обычно будет содержать вызовы правил / токенов / регулярных выражений / методов более низкого уровня. Аналогично, автономное правило / регулярное выражение может содержать обращения к другим правилам / регулярным выражениям. Каждый такой вызов будет включать создание другого нового объекта грамматики / соответствия, который становится инвокантом для вложенного вызова. Если вложенный вызов совпадает, и это вызов захвата, то новый объект грамматики / сопоставления добавляется в объект грамматики / сопоставления более высокого уровня.

  • [1 171]
2
ответ дан raiph 27 June 2019 в 18:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: