Есть ли разумная причина, почему конструктор массива Perl 6 сглаживает свой аргумент?

Учитывая один аргумент, конструктор Array сглаживает его. Это вызывает проблемы:

my %hash = (a => 1; b => 2);
my @array = [ %hash ]; # result: [a => 1 b => 2], expected [{ a => 1, b => 2 }]

Конструктор списка не имеет этого quirk (правило одного аргумента), но, к сожалению, не существует короткого синтаксиса для создания однострочного правила, список элементов:

List.new(%hash); # result is ({a => 1, b => 2}), as expected

Обходной путь: если ваш аргумент является скаляром, он не будет автоматически сглаживаться:

my $hash = %hash;
my @array = [ $%hash ]; # or my @array = [ $%hash ], or just my @array = $%hash
# result: [{a => 1, b => 2}], as expected

Другим обходным решением является добавление запятой в конец списка элементов:

my @array = [ %hash, ];

Реальная проблема заключается в том, когда мы выписываем данные буквально. Представление JSON-подобной вложенной структуры в Perl 6 является реальной проблемой, если 1-элементные списки сглажены, но других списков нет. Данные оказались неправильными. Мне пришлось записывать много данных при использовании MongoDB, поскольку аргументы MongoDB API должны быть отформатированы как вложенные списки/массивы. Это было почти невозможно. Поэтому я спрашиваю, в чем заключается мотивация сглаживания одного элемента массива?

Ответ 1

Мотивация сглаживания одного элемента массива состоит в том, чтобы последовательно применять одно правило аргумента. Конструктор массива [ ] также следует за единственным правилом аргумента. Может быть, это помогает думать о [%h] как infix:<[ ]>(%h), что и есть на самом деле. Если вы не хотите сглаживания, вы можете либо пометить его (префикс a $), либо, как вы показали, добавить запятую, чтобы сделать ее List. Это следует за той же логикой, что и ($a), как и $a, но ($a,) является List с одним элементом $a.

my %h = a => 42, b => 666;
dd [%h];     # [:a(42), :b(666)]
dd [%h,%h];  # [{:a(42), :b(666)}, {:a(42), :b(666)}]
dd [%h,]     # [{:a(42), :b(666)},]  make it a List first
dd [$%h]     # [{:a(42), :b(666)},]  itemize the Hash

Ответ 2

Сигл @в Perl указывает "эти", а $указывает "the". Этот вид множественного/единственного различия проявляется в разных местах на языке, и из него очень удобно использовать Perl. Сглаживание - это идея, что @-подобная вещь будет в определенных контекстах иметь свои значения, автоматически включенные в окружающий список. Традиционно это был источник как великой силы, так и большой путаницы в Perl. Perl 6 прошел через ряд моделей, связанных с уплощением во время его эволюции, прежде чем опираться на простой, известный как "правило единственного аргумента".

Единственное правило аргумента лучше понять, учитывая количество итераций, которые будет выполняться циклом for. Вещь для итерации всегда рассматривается как один аргумент цикла for, поэтому имя правила.

for 1, 2, 3 { }         # List of 3 things; 3 iterations
for (1, 2, 3) { }       # List of 3 things; 3 iterations
for [1, 2, 3] { }       # Array of 3 things (put in Scalars); 3 iterations
for @a, @b { }          # List of 2 things; 2 iterations
for (@a,) { }           # List of 1 thing; 1 iteration
for (@a) { }            # List of @a.elems things; @a.elems iterations
for @a { }              # List of @a.elems things; @a.elems iterations

из Synopsis7 https://design.perl6.org/S07.html#The_single_argument_rule

Ответ 3

Мотивация для оператора построения массива с использованием правила 1-arg:

  • Потому что это действительно просто оператор circumfix, а не специальный синтаксис.
    Другие операторы/ключевые слова, которые ожидают потенциально вложенного списка в качестве входных данных, используют правило с одним аргументом, поэтому для согласованности это тоже делает.

Мотивация для операторов преобразования/ключевых слов в общем случае с использованием правила 1-arg:

  • Чтобы облегчить общий случай, когда весь список ввода уже сохранен в переменной один.
  • Чтобы избежать дальнейших специальных запятых специальной ячейки.
    У операторов нет списков аргументов, таких как функции; они принимают только один объект в качестве своего аргумента (операторы унарного/огибающего) или по одному с каждой стороны (двоичные операторы). Выражение @a, создает один элемент List, поэтому, передавая результат этого выражения в оператор преобразования списка, он считает, что List точно так же, как он обрабатывал бы любые другие неконтейнерные Iterable, переданные it: Он выполняет итерацию и действует на свой элемент (ы).
  • Тот факт, что аргумент не повторяется, когда он завернут в контейнер элемента (т.е. переменную $), предназначен для сохранения сингулярно-множественного различия сигил, поскольку @p6steve.

Здесь указанная согласованность, продемонстрированная с использованием одного ключевого слова, одного двоичного оператора и одного оператора circumfix:

for @a { ... }      # n iterations
for @a, { ... }     # 1 iteration
for @a, @b { ... }  # 2 iterations

for $a { ... }      # 1 iteration


1..Inf Z @a      # new Seq of n elements
1..Inf Z @a,     # new Seq of 1 element
1..Inf Z @a, @b  # new Seq of 2 elements

1..Inf Z $a      # new Seq of 1 element


[ @a ]      # new Array with n elements
[ @a, ]     # new Array with 1 element
[ @a, @b ]  # new Array with 2 elements

[ $a ]      # new Array with 1 element

Как насчет подпрограмм/методов?

У них есть списки аргументов, поэтому правило с одним аргументом для них не так естественно, как для операторов.

Обратите внимание, что в области верхнего уровня списка аргументов запятые не создают List – они разделяют аргументы.

Подпрограммы/методы, которые рассматриваются как подпрограммы "преобразования списка", которые ожидают потенциально вложенные списки в качестве входных данных, по-прежнему участвуют в правиле однократного использования, проверяя, получили ли они один аргумент или несколько, и если только один, обернута в контейнер элементов:

map {...}, @a;      # n iterations
map {...}, (@a,);   # 1 iteration (Parens needed to get a List-constructing comma.)
map {...}, @a, @b;  # 2 iterations

map {...}, $a;      # 1 iteration

Пользовательские подпрограммы могут легко получить это поведение, используя подпись [email protected].