Я могу страдать от угасания мозгов, но, согласно документам, касающимся назначения предметов и списков (https://docs.raku.org/language/variables#Item_and_list_assignment),
Назначение контейнеру списка (список-контекст) всегда запускает назначение списка.
Однако это, похоже, противоречит тому, что я получаю из кода (здесь воспроизведено в ответе raku).
> my %syns-by-name = %(Bq => ["Bq", "becquerel", "becquerels"], C => ["C", "coulomb", "coulombs"],)
{Bq => [Bq becquerel becquerels], C => [C coulomb coulombs]}
> my Str @res = %syns-by-name{'Bq'};
Type check failed in assignment to @res; expected Str but got Array (["Bq", "becquerel", ...) in block <unit> at <unknown file> line 1
> my Str @res = [|%syns-by-name{'Bq'}];
[Bq becquerel becquerels]
Это ошибка, или я неправильно понимаю цель...?
Welcome to 𝐑𝐚𝐤𝐮𝐝𝐨™ v2020.10.
Implementing the 𝐑𝐚𝐤𝐮™ programming language v6.d.
Built on MoarVM version 2020.10.





TL;DR Если неродной элемент можно изменить с помощью присваивания, это Scalar. Назначение списка не сглаживает Scalar элементы. [1]
Рассмотрим этот код:
my %map = :a;
%map<a> = 42;
say %map<a>; # 42
Задание работает, потому что:
say %map<a>.VAR.WHAT; # (Scalar)
Рассмотрим этот код:
my $scalar = 1,2; # Useless use of constant integer 2
say $scalar; # 1
my @list1 = 1,2; # "list assignment", so RHS is iterated
say @list1; # [1 2]
Так что это одно различие между назначением элемента и списка.
my @list3 = [1,2]; # Again, RHS is iterated
say @list3; # [1 2]
my @list2 = (1,2); # Again, RHS is iterated
say @list2; # [1 2]
my @list4 = 1,(2,3); # Again, RHS is iterated. Second element stays as a `List`.
say @list4; # [1 (2 3)]
my @list5 = 1,[2,3]; # Again, RHS is iterated. Second element stays as an `Array`.
say @list5; # [1 [2 3]]
Если в RHS указан только один элемент, и это не Scalar, присвоение списка сглаживает его. Но во всех других сценариях назначение списка не выравнивает элементы.
my @list6 = $[1,2]; # RHS is a `Scalar`. So it doesn't get flattened.
say @list6; # [[1 2]]
Разбираем ситуацию в вопросе:
my Str @res = %( :a[42,99] )<a>;
Это дает такую же ошибку.
Потому что:
say .VAR.WHAT given :a[42,99]<a>; # (Array)
say .VAR.WHAT given (% = :a[42,99])<a>; # (Scalar)
[1] Когда предположение приводит к удивлению, и вы превращаете его в обучение, вы осознаете и идеализируете свои инвестиции в ERNing.
Итак, чтобы проверить мое понимание, в раку, когда у вас есть массив в качестве значения хэша, он представляется обратно как скаляр при доступе?
«(ii) вам нужно дважды декантировать его, если вы хотите получить список». (Я бы посоветовал придерживаться строчной буквы «список», а не «список», потому что это не связано с типом List, а просто списками в самом общем смысле и, в частности, «назначением списка».) Никогда не нужно несколько deconts (например, постфикс <>s) в любом коде Raku, потому что внутри Scalar никогда не может быть Scalar. Так что, если вам когда-нибудь понадобится деконтаминация, одной деконтаминации всегда достаточно.
Упс - удалил свои первые ответы - извиняюсь. Мне ясно - ценю руководство!! Не стесняйтесь удалять/изменять свои ответы на мои ответы - отложу до завтра.
«Итак, чтобы проверить мое понимание, в раку, когда у кого-то есть массив как значение хэша, он представляется обратно как скаляр при доступе «если нет Scalar» (например, как показано в конце моего комментария о «(i) . .."), то это Array, чистое и простое. Нет Scalar, содержащего Array. Но если Array (или любое другое значение) содержится в Scalar (что вы можете проверить, вызвав для него .VAR.WHAT), то функции, которые проверяют VAR.WHAT объекта (я думаю, это просто сглаживание?), обнаружат, что это Scalar, и сработают. соответственно. Для других функций Scalar даст значение, которое оно содержит.
@ p6steve Я буду спать на этом, но я думаю, что, вероятно, включу дополнительное обучение, которое происходит для нас обоих из-за нашего обмена, здесь, в комментариях, в ответ, а затем удалю свои комментарии. Я, вероятно, также уберу ERN из сноски, потому что это просто прихоть и плохо подходит для того, что я действительно хочу передать, потому что ERN на самом деле касается двигательной реакции в сочетании с умственной активностью, что здесь не применимо, тогда как то, что я хочу подчеркнуть, - это комбинация предположения => неожиданности (см. DWIM / WAT), которую я научил себя всегда получать и превращать в возможность обучения.
Привет @raiph - это все круто - я узнал немного больше, ценю диалог!!
Примечание: вы не ошибетесь, прочитав ответ @raiphs. Тем не менее, я попытаюсь объяснить, что здесь происходит, и предложить возможные решения.
В Раку контекст - это все. Это означает, что разные контексты запускаются в разных контекстах, что подразумевает разные функции упаковки или распаковки структуры данных, с которой вы работаете.
Давайте посмотрим на это
my %syns-by-name = %(Bq => ["Bq", "becquerel", "becquerels"], C => ["C", "coulomb", "coulombs"],)
Мы знаем, что находимся в «ассоциативном» контексте, потому что проценты отмечают обе стороны знака равенства. Нам даже не понадобится это с правой стороны:
my %syns-by-name = Bq => ["Bq", "becquerel", "becquerels"], C => ["C", "coulomb", "coulombs"]
потому что, глядя на левый, это все еще ассоциативный, так что мы знаем, что у нас в руках. Тот же самый код rhs в этом контексте:
my @list-of-signs = Bq => ["Bq", "becquerel", "becquerels"], C => ["C", "coulomb", "coulombs"] # [Bq => [Bq becquerel becquerels] C => [C coulomb coulombs]]
Выдаст список пар. Итак, мы проверяем, что вы упомянули в своем ОП:
Назначение контейнеру списка (список-контекст) всегда запускает назначение списка.
правдиво. Это контейнер «список», мы превращаем rhs в список только по контексту. Здесь нет никакой двусмысленности: правая часть — это список, разделенный запятыми, левая — позиционный. Так вот.
Ситуация немного отличается в вашем коде. Возможно, это станет немного яснее, если мы будем использовать 2020.12.
my %syns-by-name = Bq => ["Bq", "becquerel", "becquerels"], C => ["C", "coulomb", "coulombs"]
my Str @res = %syns-by-name{'Bq'};
# Type check failed in assignment; expected Positional[Str] but got Array ($["Bq", "becquerel", ...)
На первый взгляд разницы не видно, поэтому я выделю ее здесь:
Ошибка проверки типа при привязке; ожидал Positional[Str], но получил Array ($["Bq", "becquerel", ...)
Это показывает, что массив детализирован, он упакован так, чтобы его можно было вписать в скалярную вещь, такую как значение хэш-ключа. По умолчанию значения хэша являются скалярными, и это включено в их определение:
role Associative[::TValue = Mu, ::TKey = Str(Any)] { }
Итак, то, что вы упомянули, остается в силе: назначение списка запускается, как в «контексте списка». Однако отдельный элемент можно преобразовать в список только одним способом: сделав его единственным элементом в списке. Если вы внимательно посмотрите на отчет об ошибке, то увидите, что он говорит: эй, ты сказал мне, что собираешься дать мне список Strs. Это не то! Это список (детализированных) массивов! Это работает:
my List @res = %syns-by-name{'Bq'};
# [(Bq becquerel becquerels)]
Что нам нужно сделать, так это «распаковать» эту штуку, то есть получить массив, который населяет скаляр. Очень просто:
my Str @res = %syns-by-name{'Bq'}<>;
# [Bq becquerel becquerels]
Оператор de-cont (который, возможно, следует называть оператором «unbox», «de-Scalarize» или «de-itemize») делает то, что нужно для вас. Однако это, вероятно, не то, что вы хотите. Вы хотите, чтобы ваши массивы были массивами. Однако это оказалось немного сложнее, и мне понадобится еще один вопрос SO, чтобы решить его.
Спасибо @JJ - я очень ценю объяснение. Это хороший, последовательный дизайн, чтобы значение хэша всегда было скаляром. Просто нужно знать, что массив будет назначен как один элемент, если вы не хотите сглаживать (|) или распаковывать (<>).
«(i)
Array, сохраненное как значениеHash, содержится вScalar». Любое значение, сохраненное как значениеHash, по умолчанию хранится вScalar. То же самое верно даже для так называемых неизменяемыхMaps. (Но, я полагаю, не будет вообще, по умолчанию или иным образом, с грядущими полностью неизменяемымиDicts.) Но любое значение может быть привязано к устранениюScalar, напримерsay .VAR.WHAT given (% := :a[42,99])<a>; # (Array).