цветочков пошли ягодки.
Итак сегодня работаем без return!
В качестве примера умножим поэлементно пару векторов и отнимем третий:
(1, 2, 3) >>*<< (2, 3, 4) >>-<< (3, 4, 5)
Для этого в perl6 имеются гипероператоры - http://laziness-impatience-hubris.blogspot.com/2009/01/perl6.html.
Но сейчас разговор не о perl6, а о perl5. Вот код, который выполняет вышеупомянутые действия:
sub mul(\@\@) {
my ($x, $y) = @_;
map { $$x[$_] * $$y[$_] } 0 .. $#$x;
}
sub minus(\@\@) {
my ($x, $y) = @_;
map { $$x[$_] - $$y[$_] } 0 .. $#$x;
}
my @i = (1, 2, 3);
my @j = (2, 3, 4);
my @k = (3, 4, 5);
my @ij = mul(@i, @j);
my @r = minus(@ij, @k);
print join(" ", @r), "\n";
Хотя в этом коде return явно не прописан он присутствует.
Обе подпрограммы возвращают результаты в виде списков.
Теперь попробуем избавиться от return. Сразу говорю, что модификация передаваемого по ссылки массива, - это не наш путь.
Не для того существует perl, чтобы на нем писать с C стиле.
Мы пойдем другим путем, похожем на стиль передачи продолжений.
Подпрограммы не будут возвращать результат, а будет вызывать другие, передавая им результат в качества аргументов,
например, вот так:
mul(@i, @j, sub { minus(@_, @k, sub { say(@_, sub {}) }) });
Или вот так, чтобы было удобней работать с параметрами подпрограмм,
ссылку на подпрограмму сделаем первой, а не последней среди передаваемых параметров:
mul(sub { minus(sub { say( sub {}, @_) }, @_, @k) }, @i, @j);
Что, при использовании магии прототипов, можно записать следующим образом:
mul { minus { say {} @_ } @_, @k } @i, @j;
Соответственно, подпрограммы в качестве первого параметра принимают ссылку на подпрограмму,
которую и вызывают, передав ей результат своей работы:
sub mul(&\@\@) {
my ($sub, $x, $y) = @_;
my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;
$sub->(@r);
}
sub minus(&\@\@) {
my ($sub, $x, $y) = @_;
my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;
$sub->(@r);
}
sub say(&@) {
my $sub = shift;
print join(" ", @_), "\n";
$sub->();
}
my @i = (1, 2, 3);
my @j = (2, 3, 4);
my @k = (3, 4, 5);
mul { minus { say {} @_ } @_, @k } @i, @j;
Вот и все. Поставленная задача выполнена. Теперь немного порассуждаем.
Подпрограммы в вышеприведенном коде можно разбить на два типа:
1) подпрограммы-кирпичики (mul, minus, say);
2) подпрограммы-клей (анонимные подпрограммы).
Подпрограммы-клей связывают подпрограммы-кирпичики.
Подпрограммы-клей содержат основную логику программы, а подпрограммы-кирпичики - это повторно используемый код.
Этот стиль очень любят использовать там, где подпрограммы являются сущностями высшего порядка.
В perl также для него есть своя ниша, но об этом позже.
Комментариев нет:
Отправить комментарий