2. Что такое мультифункции в Perl 6

В Perl 6 есть ключевое слово multi, которое создает так называемые мультифункции (multi-subs). Это ни что иное как множественная диспетчеризация (multiple dispatch), встроенная в язык.

В отличие от обычных функций, которые объявляются со словом sub, мультифункции требуют двух слов: multi sub. Имя функции при этом остается одним и тем же для всего набора мультифункций. В зависимости от выполненных условий, компилятор выбирает один из вариантов функции.

Число аргументов

Рассмотрим несколько примеров. Первый пример — вычисление расстояния от начала координат до точки на прямой, на плоскости или в трехмерном пространстве.

multi sub dist($x) {
    return $x;
}

multi sub dist($x, $y) {
    return sqrt($x ** 2 + $y ** 2);
}

multi sub dist($x, $y, $z) {
    return sqrt($x ** 2 + $y ** 2 + $z ** 2);
}

say dist(2);        # 2
say dist(3, 4);     # 5
say dist(8, 9, 12); # 17

В этом примере функции различаются исключительно числом аргументов. При вызове, Perl 6 однозначно определяет, какой из вариантов следует вызвать.

Типы аргументов

Второй пример использует для выбора тип аргумента. Совсем не обязательно для этого создавать собственные классы, можно начать с типов, встроенных в язык.

multi sub mirror(Int $i) {
    -$i
}

multi sub mirror(Str $s) {
    $s.flip
}

say mirror(42);   # -42
say mirror('42'); # 24

Здесь функция возвращает должна вернуть «зеркальный» вариант своего аргумента, чтобы это ни значило. Точный смысл вы в праве установить самостоятельно для каждого типа аргумента. Для целых чисел (Int $i) это будет противоположное число, а для строки (Str $s) — строка, записанная в обратном порядке.

Точно так же возможно определить свой класс и дополнить мультифункцию соответствующим вариантом. Во-первых, определим класс для светофора, у которого есть текущее значение value. Во-вторых, создадим мультифункцию, которая ожидает такой объект и инвертирует его:

class TrafficLight {
    has Str $.value;
}

multi sub mirror(TrafficLight $obj) {
    $obj.value eq 'red' ?? 'green' !! 'red'
}

say mirror(TrafficLight.new(value => 'green')); # red

Ограничение на значение аргументов

Еще один вариант — выбор одной из мультифункций, опираясь на значение аргументов. Для простоты рассмотрим простейший вариант функции с одним аргументом, которая для коротких слов печатает предупреждение о том, что пароль слишком короткий:

multi sub set-password($pwd) {
    say "Password '$pwd' is OK"
}

multi sub set-password($pwd where {$pwd.chars <= 5}) {
    say "Password '$pwd' is too short!"
}

set-password('He11oW0rld!'); # OK
set-password('qwert');       # too short!

Во втором варианте функции значение аргумента уточняется с помощью ключевого слова where:

multi sub set-password($pwd where {$pwd.chars <= 5}) { . . . }

Эта функция будет вызвана только в том случае, если выполняется условие $pwd.chars <= 5, то есть когда строка недостаточно длинна.

Обратите внимание, что для первого варианта функции никаких ограничений нет, тем не менее, Perl 6 принимает совершенно правильно решение, опираясь на весь комплект функций, и не активирует этот вариант для короткой строки.

На сегодня все. Завтра будем использовать мультифункции для создания рекурсии.

One thought on “2. Что такое мультифункции в Perl 6”

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *