Что означает точка перед постфиксом или постфиксом в Perl 6?
В документации по Perl есть раздел о .postfix /.postcircumfix, там говорится, что
В большинстве случаев точка может быть помещена перед постфиксом или постфиксом:
my @a;
@a[1, 2, 3];
@a.[1, 2, 3]; # Same
Технически, не настоящий оператор; это специальный синтаксис в компиляторе.
Я попробовал себя:
> my @a = 1,2,3,4,5
> @a[1] # 2
> @a.[1] # 2
> my %a = Perl => 6, Python => 3, PHP => 7
> %a<Perl> #6
> %a.<Perl> #6
> my @weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
> @weekdays.antipairs.hash{'Sunday'} # 6, I expected it to be syntax wrong, but it did work!
> @weekdays.antipairs.hash.{'Sunday'} # 6, seems visual clarity or brevity
Итак, что означает точка перед постфиксом или постфиксом в Perl 6? Как же он это сделал? Мне интересно об этом. Благодарю.
1 ответ
Выражение в Perl 6 анализируется как termish
вещи с infixish
вещи между ними. termish
в свою очередь определяется как ноль или более prefixish
вещи, за которыми следует сам термин, за которым следует ноль или более postfixish
вещи. postfixish
принимает во всех:
- Вызовы методов (например,
.foo
) - Постфиксные операторы (как
++
) - Операторы Postcircumfix (например,
[42]
в@a[42]
) - Занимаюсь гипер (
>>
) на них, чтобы распределить их по структуре данных
Поскольку он просто ищет ноль или более из них, вы можете свободно чередовать вызовы методов и индексы хешей и массивов. Это объясняет почему @weekdays.antipairs.hash{'Sunday'}
разбирает нормально (а почему @weekdays.antipairs.hash<Sunday>
также будет работать, и даже @weekdays.antipairs.hash<Sunday>.say
тоже хорошо).
Для .
Грамматика просто принимает и игнорирует .
перед postfix
или postcircumfix
, Вот немного урезанная версия парсера, которую я немного аннотировал, чтобы объяснить, что это за штуки.
token postfixish {
<!stdstopper>
# If we're not in a string interpolation, allow unspace (that's
# where you write `\ ++`, for example, allowing spreading
# postfixish things over multiple lines).
[ <!{ $*QSIGIL }> [ <.unsp> | '\\' ] ]?
# Here we match the >> for doing a hyper. Note that it accepts
# but disregards a '.' before it. It's not captured at all and
# doesn't affect the code that is compiled.
[ ['.' <.unsp>?]? <postfix_prefix_meta_operator> <.unsp>?]**0..1
[
| <OPER=postfix>
# When there'd be no confusion with a method call, a '.' is
# also accepted and disregarded before a postfix operator
| '.' <?before \W> <OPER=postfix> ## dotted form of postfix operator (non-wordy only)
| <OPER=postcircumfix>
# Ditto here for recognized postcircumfixes
| '.' <?[ [ { < ]> <OPER=postcircumfix>
| <OPER=dotty>
| <OPER=privop>
]
}
Таким образом .
вообще ничего не значит в этом контексте. Синтаксический анализатор просто принимает его, а затем переходит к поиску того, что ему действительно нужно в тот момент.
Еще одна вещь, на которую стоит обратить внимание, это то, что операторы postfix и postcircumfix тоже работают после точечного термина и работают на $_
, Таким образом:
my @xs = 1..10;
.++ for @xs;
say @xs;
Будет производить:
[2 3 4 5 6 7 8 9 10 11]
Вот пример postcircumfix:
my %h = a => 1, b => 2, c => 3;
say .<a> + .<c> given %h;
Который производит 4
,
Синтаксис Perl 6 обычно предназначен для того, чтобы упростить перенос кода из одной формы в другую и принимать .
в местах, даже там, где это не является строго необходимым, это немного облегчает (так что можно say %h1.<a> + %h2.<b>;
и с парсером все будет в порядке). Это также может быть полезно в учебных целях, чтобы рассмотреть %h<a>
Короче для %h.<a>
что в свою очередь сделало бы .<a> given %h
чуть меньше сюрприза.
Дополнительное пространство, предоставленное .
может также помочь в ясности, особенно если нужно было сложить несколько постфиксов, и даже может - если по какой-то причине расширение языка решит определить некоторые "интересные" термины или операторы постфикса - послужит средством устранения неоднозначности.
Это действительно имеет значение, когда у вас есть саб, который возвращает Callable
,
sub foo { 'hello' }
sub bar { &foo; }
bar.WHAT # (Sub)
bar().WHAT # (Sub)
bar.().WHAT # (Str)
bar()().WHAT # (Str)
bar().().WHAT # (Str)
bar.().().WHAT # No such method 'CALL-ME' for invocant of type 'Str'