Как операции с наборами Perl 6 сравнивают элементы?

Бег под мором (2016.10)

Рассмотрим этот код, который создает набор и проверяет членство:

my $num_set = set( < 1 2 3 4 > );
say "set: ", $num_set.perl;
say "4 is in set: ", 4 ∈ $num_set;
say "IntStr 4 is in set: ", IntStr.new(4, "Four") ∈ $num_set;
say "IntStr(4,...) is 4: ", IntStr.new(4, "Four") == 4;
say "5 is in set: ", 5 ∈ $num_set;

Прямого 4 нет в наборе, но версия IntStr:

set: set(IntStr.new(4, "4"),IntStr.new(1, "1"),IntStr.new(2, "2"),IntStr.new(3, "3"))
4 is in set: False
IntStr 4 is in set: True
IntStr(4,...) is 4: True
5 is in set: False

Я думаю, что большинство людей этого не ожидает, но в документах ничего не говорится о том, как это может работать. У меня не будет этой проблемы, если я не использую цитаты (например, set( 1, 2, 3, 4)).


person brian d foy    schedule 26.11.2016    source источник


Ответы (5)


Вы ошиблись в середине. Важная часть - это то, с чем вызывается nqp::existskey: k.WHICH. Этот метод предназначен для типов значений, то есть неизменяемых типов, где значение, а не идентичность, определяет, должны ли две вещи быть одним и тем же (даже если они созданы дважды). Он возвращает строковое представление значения объекта, равного для двух вещей, которые должны быть равны. За <1>.WHICH вы получаете IntStr|1, а за 1.WHICH вы получаете только Int|1.

person timotimo    schedule 26.11.2016
comment
Ах хорошо. Я вижу много боли для обычных людей, пытающихся отладить эти вещи. - person brian d foy; 26.11.2016

Как объясняется в документации Set, устанавливает идентичность объекта сравнения, как и _ 1_ оператор:

Внутри Set каждый элемент гарантированно уникален (в том смысле, что никакие два элемента не будут положительно сравниваться с оператором ===)

Идентичность объекта определяется методом .WHICH, как поясняет Тимотимо в своей отвечать.

person smls    schedule 26.11.2016
comment
Это не совсем ясно из этого заявления. Речь идет о том, какие элементы входят в набор. Кроме того, даже если вы решите сравнить с ===, вы должны знать, как хранятся другие вещи. Это информация, которая должна отображаться рядом с операторами Set. - person brian d foy; 27.11.2016
comment
Действительно, я думаю, что нашел ошибку. Документы qw говорят, что это должно быть правдой: < a b 137 > eqv ( 'a', 'b', '137' ), но в той же версии Rakudo Star я получаю ложь. С каждой стороны разные типы объектов. - person brian d foy; 27.11.2016
comment
Несмотря на все это, ваш ответ был А-ха! момент, который заставил меня взглянуть на то, что нужно. Спасибо за всю твою помощь. - person brian d foy; 27.11.2016

Напишите свой список чисел, используя запятые

Как вы упомянули в своем ответе, ваш код работает, если вы пишете свои числа в виде простого списка, разделенного запятыми, а не с помощью конструкции <...>.

Вот почему:

4 ∈ set 1, 2, 3, 4 # True

Пустой числовой литерал в коде, такой как 4 слева от , создает одно значение с числовым типом. (В данном случае это целое число Int.) Если конструктор set получает список похожих литералов справа, тогда все работает нормально.

<1 2 3 4> создает список двойных значений.

Различные конструкции <...> цитируют слова, переворачивают список буквальных элементов, разделенных пробелами внутри угловые скобки в выходной список значений.

Базовый вариант (qw<...>) выводит только строки. Использование его в вашем случае не работает:

4 ∈ set qw<1 2 3 4> # False

4 слева составляет одно числовое значение типа Int. Тем временем конструктор set получает список строк типа Str: ('1','2','3','4'). Оператор не находит Int в наборе, потому что все значения равны Str, поэтому возвращает False.

Двигаясь дальше, вариант huffmanized <...> выводит Strs, если элемент не распознается как число. Если элемент распознается как число, то выходное значение - двойное значение. Например, 1 становится IntStr.

Согласно документу IntStr может использоваться взаимозаменяемо, где можно использовать Str или Int. Но может ли это?

Ваш сценарий - яркий тому пример. В то время как 1 ∈ set 1,2,3 и <1> ∈ set <1 2 3> работают, 1 ∈ set <1 2 3> и <1> ∈ set 1, 2, 3 оба возвращают False.

Таким образом, похоже, что оператор не соответствует заявлению процитированного документа о взаимозаменяемости двойных значений.

Это может быть уже признано ошибкой в ​​ операции установки и / или других операциях. Даже если нет, этот острый край двойного значения конструктора списка <...> может в конечном итоге рассматриваться как достаточно болезненный, что Perl 6 необходимо изменить.

person raiph    schedule 27.11.2016

Думаю, это баг, но не в наборе. Другие ответы очень помогли разобраться в том, что было важным, а что нет.

Я использовал форму кавычек в угловых скобках. Форма цитатных слов должна быть эквивалентна цитируемой версии (то есть True в eqv). Вот пример документа:

<a b c> eqv ('a', 'b', 'c')

Но когда я пробую это со словом, состоящим только из цифр, это не работает:

 $ perl6
 > < a b 137 > eqv ( 'a', 'b', '137' )
 False

Но другие формы работают:

> qw/ a b 137 / eqv ( 'a', 'b', '137' )
True
> Q:w/ a b 137 / eqv ( 'a', 'b', '137' )
True

В кавычках угловых скобок используется IntStr:

> my @n = < a b 137 >
[a b 137]
> @n.perl
["a", "b", IntStr.new(137, "137")]

Без кавычек слово цифр выглядит как [Str]:

> ( 'a', 'b', '137' ).perl
("a", "b", "137")
> ( 'a', 'b', '137' )[*-1].perl
"137"
> ( 'a', 'b', '137' )[*-1].WHAT
(Str)
> my @n = ( 'a', 'b', '137' );
[a b 137]
> @n[*-1].WHAT
(Str)

Обычно вы видите ошибки такого рода, когда есть два пути кода для получения окончательного результата, а не общий код, который очень рано сходится к одному пути. Это то, что я бы искал, если бы хотел отследить это (но мне нужно поработать над книгой!)

Однако это подчеркивает, что вы должны быть очень осторожны с наборами. Даже если эта ошибка была исправлена, есть и другие, не связанные с ошибками способы eqv могут выйти из строя. Я бы все равно потерпел неудачу, потому что 4 как Int не равно «4» как Str. Я думаю, что такой уровень внимания к типам данных неадекватен в DWIMery. Это определенно то, что мне пришлось бы очень осторожно объяснять в классе и при этом наблюдать, как все на этом не ладят.

Как бы то ни было, я думаю, что результаты gist имеют тенденцию вводить в заблуждение из-за их чрезмерного упрощения, а иногда результаты perl недостаточно богаты (например, скрытие Str, что вынуждает меня .WHAT). Чем больше я их использую, тем менее полезными я считаю их.

Но знание того, что я напортачил еще до того, как я начал, спасло бы меня от этой спелеологии кода, которая в конечном итоге ничего не значила!

person brian d foy    schedule 26.11.2016
comment
Не могли бы вы пояснить, что вы считаете ошибкой? Насколько я могу судить, это все задумано: (а) <...> проходит через &val , который, если возможно, возвращает алломорфы (б) членство в множестве определяется в терминах идентичности, которая различает алломорфы и соответствующие им типы значений; так что я бы не классифицировал это как ошибку, я бы сказал «сломанный» по дизайну; или другими словами, это просто WAT, который поставляется с этим конкретным DWIM - person Christoph; 27.11.2016
comment
Это было добавлено намеренно и является - person Brad Gilbert; 27.11.2016
comment
Здесь документация кажется неправильной, <...> не соответствует qw(...), а qw:v(...). См. Описание наречия в S02 и этот тест, который ‹del› искал‹ / del ›уже связан с - person Christoph; 27.11.2016
comment
или, возможно, не совсем неправильно, а скорее «просто» вводит в заблуждение: <...> действительно является формой :w, и данный пример кода действительно сравнивает равным согласно eqv - person Christoph; 27.11.2016
comment
Zoffix исправил документы в github.com/perl6/doc/commit/. - person brian d foy; 27.11.2016
comment
@raiph Думаю, тебе стоит восстановить свой ответ. Это хороший материал. Я думаю, что Perl 6 находится на том сложном этапе, когда он работает и имеет смысл для людей, создающих его, но теперь пришло время для людей, которые просто хотят его использовать. Это другая аудитория, которая сдастся гораздо раньше, чем я. Изменения Zoffix в документации имеют большое значение для этого. - person brian d foy; 27.11.2016
comment
@raiph, что имеет смысл :) - person brian d foy; 28.11.2016

Просто чтобы добавить к другим ответам и указать на согласованность здесь между наборами и хешами объектов .

Хэш объекта объявлен как my %object-hash{Any}. Этот метод эффективно хеширует объекты .WHICH, аналогично тому, как наборы различают отдельные элементы.

Подстановка набора хешем объекта:

my %obj-hash{Any};

%obj-hash< 1 2 3 4 > = Any;
say "hash: ", %obj-hash.keys.perl;
say "4 is in hash: ", %obj-hash{4}:exists;
say "IntStr 4 is in hash: ", %obj-hash{ IntStr.new(4, "Four") }:exists;
say "IntStr(4,...) is 4: ", IntStr.new(4, "Four") == 4;
say "5 is in hash: ", %obj-hash{5}:exists;

дает результаты, аналогичные вашему исходному примеру:

hash: (IntStr.new(4, "4"), IntStr.new(1, "1"), IntStr.new(2, "2"), IntStr.new(3, "3")).Seq
4 is in hash: False
IntStr 4 is in hash: True
IntStr(4,...) is 4: True
5 is in hash: False
person dwarring    schedule 27.11.2016
comment
Я согласен, что это не здорово, как есть. - person dwarring; 30.11.2016