Как треугольная редукция оператора запятой узнает, чтобы составить список всех списков? - PullRequest
0 голосов
/ 16 декабря 2018

В Perl 6 при треугольном сокращении оператора запятой создается список списков, каждый из которых добавляет один последовательный элемент из списка ввода:

> [\,] 1..5
((1) (1 2) (1 2 3) (1 2 3 4) (1 2 3 4 5))

Довольно приятно!Но недавно мне стало интересно, как это работает так, как работает.

Если op - произвольный оператор, [op] @list должен быть таким же, как @list[0] op @list[1] op ... op @list[*-1].Как я понимаю, тогда [\op] должен быть списком всех промежуточных значений.Но, похоже, это должно означать, что [\op] @list должно оцениваться до (@list[0], @list[0] op @list[1], @list[0] op @list[1] op @list[2], ...).В моем исходном случае, где op равно ,, первый элемент списка вывода должен быть просто @list[0], но это не так;это одноэлементный список (@list[0],).

Как исходное треугольное сокращение знает, как сделать первый элемент его вывода одноэлементным списком?

Если я напишу свою собственную процедуру построения списка, это сработаеткак я и ожидал:

> sub foo { |$^a, $^b }
sub foo ($a, $b) { #`(Sub|93971926296448) ... }
> [[&foo]] 1..5
(1 2 3 4 5)
> [\[&foo]] 1..5
(1 (1 2) (1 2 3) (1 2 3 4) (1 2 3 4 5))

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Я собирался опубликовать, когда Джонатан опубликовал свой ответ.Я бы доверял его худшему ответу на все, что было до меня, чему угодно, но что за эй, вот что у меня было, даже если это совершенно неправильно.


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


Дело не в треугольном аспекте.Это просто соответствует базовому базовому сокращению.

Применение , к одному элементу дает список из одного элемента

Вы писали:

[\op] @listоцените (@list[0], @list[0] op @list[1], ...).

Не обязательно.В документе для процедуры сокращения (с добавленным выделением ):

Если @list содержит только один элемент, операторприменяется к этому единственному элементу, если это возможно ;если нет, он возвращает сам элемент.

Можно использовать , с одним элементом, получая один список элементов:

say .gist given 42   ; # 42
say .gist given 42 , ; # (42)
say .perl given 42 , ; # (42,)

И так:

say [,]  42;    # (42)
say [,]  42,99; # (42 99)

Таким образом, обычное сокращение с оператором запятой всегда создает список, даже если это сокращение одного элемента.А треугольная редукция просто следует за ней:

say [\,] 42;    # ((42))
say [\,] 42,99; # ((42) (42 99))
0 голосов
/ 16 декабря 2018

Это потому, что оператор infix:<,> является списочным.Ассоциативность, как правило, заключается в принятии решения о том, следует ли группировать вещи влево или вправо (или нет вообще).Perl 6 также признает, что некоторые операторы ассоциируются «плоским» способом, где мы просто хотим, чтобы все значения, разделенные оператором, были предоставлены реализации оператора сразу.

Если мы объявляем оператор со значением по умолчаниюассоциативность и используйте его:

sub infix:<a>(*@a) {
    say @a.perl;
    return @a.elems;
};
say [\a] 1..5;

Тогда он будет вызываться только с парами элементов, давая результат:

[1, 2]
[2, 3]
[2, 4]
[2, 5]
(1 2 2 2 2)

Однако измените его на ассоциативный список, добавив is assoc('list') trait:

sub infix:<a>(*@a) is assoc('list') {
    say @a.perl;
    return @a.elems;
};
say [\a] 1..5;

Тогда вместо этого получается:

[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, 4]
[1, 2, 3, 4, 5]
(1 2 3 4 5)

Именно так infix:<,> получает свое хорошее поведение по уменьшению треугольника.

...