Моя последняя небольшая статья была о специфической разнице между тем, как Perl 5 и Perl 6 генерируют диапазоны, а точнее о том, как диапазон «AAAAAAAA»...ABRAXAS генерирует более 19 миллионов элементов, тогда как Perl 6 генерирует скромные 16,416. С помощью моих читателей я выяснил, что Perl 5 рассматривает диапазон как число с основанием 26 (то есть систему счисления, где A = 0 и Z = 25). Perl 6, однако, создает диапазон, «считая» справа налево, повторяя каждый символ в «AAAAAAAA» от A до любого символа в «ABRAXAS», которому он соответствует. т.е. «A[A-B][A-R]A[A-X]A[A-X]», начиная с самой правой буквы A и продвигаясь влево.

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

После этого у меня состоялась дискуссия с Али Эльшишини, где я создал небольшой фрагмент кода, используя оператор smartmatch в Perl 6. Мы пытались использовать smartmatch, чтобы проверить, принадлежит ли AAAAOYM к диапазону. Это не так, но Perl 6 сказал, что да. Что дает?

Это легче понять, когда вы видите это:

$ perl6 -e 'say ("AAAAAAA".."ABRAXAS").grep("AAAAOYM"); say "AAAAOYM" ~~ "AAAAAAA".."ABRAXAS";'
()    # result of the grep: AAAAOYM is not in the range
True  # ...but the smartmatch operator says it is

Здесь однозначно нестыковка. Насколько я знаю, это сделано специально, но если это так, было бы интересно узнать, почему.

Но как ни странно… если вы преобразуете диапазон в массив, несоответствие исчезнет.

$ perl6 -e 'my @a = "AAAAAAA".."ABRAXAS"; say @a.grep("AAAAOYM");'
()     # result of the grep: AAAAOYM is not in the range

Я чувствую, что оператор SmartMatch, используемый в диапазоне, должен работать примерно так же, как .grep ( (@loltimo указал мне в Твиттере, что используется в массивах и списках, оператор SmartMatch ищет не членство, а эквивалентность) .

Если это так, проблема заключается в самом классе Range. Я не эксперт во внутренней работе кода Rakudo Perl 6. Но может быть проблема в строках 378–381 исходного кода класса Range (версия от 25 августа 2018 года)? Вот что он говорит:

multi method ACCEPTS(Range:D: Mu \topic) {
        (topic cmp $!min) > -(!$!excludes-min)
          and (topic cmp $!max) < +(!$!excludes-max)    
}

Видя это, я думаю, что весь разгром связан с оператором cmp. Не сам оператор, а то, как он используется. Я полагаю, что оператор cmp выполняет сравнение по алфавиту. В приведенном выше методе он используется для сравнения topic с минимальным и максимальным значениями диапазона.

Чтобы все упростить, предположим, что мы сравниваем строку с диапазоном «AAAA»..»AXAS».

AOYM не входит в этот диапазон. Но если мы, как описано выше, используем cmp для сравнения минимального и максимального значения диапазона, вы действительно поверите, что это так:

$ perl6 -e 'say "AOYM" cmp "AAAA"; say "AOYM" cmp "AXAS";'
More
Less

При рассмотрении изоляции ответ заключается в том, что AOYM меньше, чем AXAS, и больше, чем AAAA. т.е. что AOYM находится в пределах диапазона. Но, как и сейчас — в том, как Perl 6 вычисляет диапазон, AOYM не является частью диапазона (в некотором смысле ~~ обрабатывает диапазон, как если бы он был диапазоном Perl 5). Метод должен будет проверять «AOYM» на равенство каждому элементу в диапазоне, чтобы оператор smartmatch работал должным образом.

Так что делать? Преобразуйте в массив/список и используйте grep.

Вывод? Какой бы неясной ни была эта проблема, я думаю, что она не скоро появится на чьем-либо радаре. Но, надеюсь, это интересно для одного или двух человек, кроме меня :-)