среда, 20 мая 2009 г.

Сегодня без return - выворачиваем наизнанку

Похоже это уже становиться традицией - задавать задачки спозаранку.
Оказывается, существует Perl Фея, которая по утрам, когда пора вставать, будит всех Just another Perl Hacker.
О прошлом появлении Феи читайте в http://laziness-impatience-hubris.blogspot.com/2009/05/return.html

Она очень осторожна, но сегодня, устроив засаду, я ее увидел первый раз.
Фей, поняв, что я не сплю, от неожиданности смутилась, похвалила меня за решение задачи "Сегодня без return",
и тут же кокетливо спросила:
- А сможешь наоборот?!
- Это как? - удивился я.
- Ну, ведь это ты Perl Hacker, а не я - придумай, - стрельнув зелеными глазами ответила она и улетела.

Да... Озадачила...
И так, в прошлый раз мы избавились от return и это наш резерв.
Если наоборот, то возвращаем все return, и используем их чтобы, чтобы...
Неужели чтобы предотвратить вызовы подпрограммы!!!

Что-то тут не так - совсем без вызовов невозможно.
Может стоит лишь упорядочить их, централизовать в одном месте?
И будет один "большой вызов", не множество "маленьких".

Возьмем пример из предыдущей заметки и перепишем его так, что подпрограммы-кирпичики не вызывают подпрограммы-клей,
а возвращают их вместе с результатом своей работы. Получиться цепочка из подпрограмм.
А "большая вызывалка" будет получать в цикле ссылки на подпрограммы и вызывать их, передавая идущие с ними аргументы.
И так до самого конца, до пустой подпрограммы.

sub mul(&\@\@) {
my ($sub, $x, $y) = @_;
my @r = map { $$x[$_] * $$y[$_] } 0 .. $#$x;
return $sub, @r;
}

sub minus(&\@\@) {
my ($sub, $x, $y) = @_;
my @r = map { $$x[$_] - $$y[$_] } 0 .. $#$x;
return $sub, @r;
}

sub say(&@) {
my $sub = shift;
print join(" ", @_), "\n";
return $sub;
}

sub main() {
my @i = (1, 2, 3);
my @j = (2, 3, 4);
my @k = (3, 4, 5);

return mul { minus { say {} @_ } @_, @k } @i, @j;
}

# А вот и "большая вызывалка", которая все это запускает.
my $sub = \&main;
my @param = ();
do {
($sub, @param) = $sub->(@param);
} while ($sub);

В вышеприведенном коде "большая вызывалка" вызывает лишь подпрограммы-клей, которые в свою очередь вызывают подпрограммы-кирпичики.
Конечно можно сделать так, чтобы она вызывала все подпрограммы:

return \&mul, sub { \&minus, sub { \&say, undef, @_ }, \@_, \@k }, \@i, \@j;

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

Чувствую, что Фея будет довольна. Интересно только, зачем она меня подталкивает в этом направлении?
Хотя, всему свое время: скоро, наверно, узнаю.

Комментариев нет: