День 8: расчесываем ограничения
Перевод на русский язык восьмой статьи цикла Perl 6 Advent Calendar.
Мы попали в точку, где предыдущие подарки будут полезны для нынешних. Сегодня у нас двойной набор: метод comb (расческа) и идея ограничений.
Аналогично статичным типам предыдущих определений, ограничения позволяют качественнее управлять написанием подпрограмм и методов. Во многих других языках программирования вы должны передавать параметры в подпрограмму, а затем проверять введенные данные. С ограничениями вы можете проверять правильность непосредственно в объявлении.
Возьмем простой пример. Если целое число четное, то я не хочу иметь дела с этой подпрограммой. В Perl 5 вы бы написали что-то похожее на это:
sub very_odd
{
my $odd = shift;
unless ($odd % 2)
{
return undef;
}
# Process the odd number here.
}
В Perl 6 это может быть упрощено:
sub very_odd(Int $odd where {$odd % 2})
{
# Process the odd number here
}
При попытке вызова very_odd с четным числом вы получите сообщение об ошибке. Не волнуйтесь, хотя вы можете использовать возможности мультифункций чтобы дать даже числам возможность проявить себя… может быть. ;)
multi sub very_odd(Int $odd where {$odd % 2})
{
# Process the odd number here
}
multi sub very_odd(Int $odd) { return Bool::False; }
Эти ограничения могут быть полезны при сочетании с методом .comb. Что же такое .comb? Для тех, кто расчесывает свои волосы: вы обычно пользуетесь расческой, чтобы уложить отдельные волоски. Для тех, кто любит использовать .split все как раз наоборот. Этот простой фрагмент кода должен продемонстрировать как работает .comb:
say "Perl 6 Advent".comb(/<alpha>/).join('|');
say "Perl 6 Advent".comb(/<alpha>+/).join('|');
Регулярные выражения, скорее всего, будут открыты в другой день, но быстрый взгляд не будет болезненным. Первая строка будет выводить «P|e|r|l|A|d|v|e|n|t»: берется каждый буквенный символ и помещается во временный массив. Затем он соединяется с символом вертикальной черты. Вторая строка аналогична, только она захватывает столько букв, сколько сможет, отсюда результат «Perl|Advent».
Однако, сила .comb намного больше. После того как вы «расчесали» что хотели, вы можете управлять «волосками». Если у вас есть определенный набор шестнадцатеричных ASCII символов, вы можете использовать гипероператоры для преобразования каждого кусочка в ASCII эквивалент!
say "5065726C36".comb(/<xdigit>**2/)».fmt("0x%s")».chr
# Outputs "Perl6"
Помните, это Perl. Существует много способов сделать это. ☺
Со всеми подарками, что были представлены сегодня, я дам вам задачу. С помощью Kayl Hasselbacher, я смог сделать достойную версию древнего шифра Цезаря при помощи ограничений, .comb, и старого доброго .map:
use v6;
sub rotate_one( Str $c where { $c.chars == 1 }, Int $n ) {
return $c if $c !~~ /<alpha>/;
my $out = $c.ord + $n;
$out -= 26 if $out > ($c eq $c.uc ?? 'Z'.ord !! 'z'.ord);
return $out.chr;
}
sub rotate(Str $s where {$s.chars}, Int $n = 3)
{
return ($s.comb.map: { rotate_one( $_, $n % 26 ) }).join( '' );
}
die "Usage:\n$*PROGRAM_NAME string number_for_rotations" unless @*ARGS == 2;
my Str $mess = @*ARGS[0];
my Int $rotate = @*ARGS[1].Int;
say qq|"$mess" rotated $rotate characters gives "{rotate($mess,$rotate)}".|;
Я хотел бы посмотреть как остальные смогут реализовать код этого алгоритма используя Perl 6 и уже открытые подарки. В конце концов язык может получиться только лучше и удобнее.
День 8: расчесываем ограничения,
Зачем писать так длинно?
unless ($odd % 2)
{
return undef;
}
Можно ж короче:
return undef unless $odd % 2;
Ваш вариант стал не короче, а более трудным для восприятия. Именно за такие записи многие и не любят Perl.
@Ky6uk
этот вариант не стал более трудным для восприятия,
но речь шла о том, что «ограничения позволяют качественнее управлять написанием подпрограмм и методов.», и соответственно для примера и простоты восприятия продемонстрировали маленькую подпрограмму.