Как в операциях множеств 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)).

5 ответов

Решение

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

Я использовал форму угловых скобок в кавычках. Форма слов в кавычках должна быть эквивалентна версии в кавычках (то есть 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. Я думаю, что этот уровень внимания к типам данных в unperly в это DWIMery. Это, безусловно, то, что я должен был бы очень тщательно объяснить в классе и все еще наблюдать, как все облажаются.

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

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

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

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

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

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

Напишите список номеров, используя запятые

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

Вот почему:

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

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

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

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

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

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

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

Двигаясь вперед, униженный <...> вариантные выводы Str s, если элемент не распознается как число. Если элемент распознается как число, то выходным значением является "двойное значение". Например, 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 необходимо изменить.

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

Хеш объекта объявлен как 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
Другие вопросы по тегам