Dado que a solução com recursão tinha duas funções bem parecidas, o natural é subir um nível na abstração e criar uma função para criar funções.
#!/usr/bin/perl
use strict;
use warnings;
no warnings 'recursion';
sub make_fizzbuzz {
  my ($callback, $factor, $word)=@_;
  return sub {
    my $n=shift || 1;
    my $multiple=shift || 0;
    if($n % $factor == 0) {
      print $word;
      $multiple=1;
    }
    $callback->($n, $multiple);
  }
}
my $fizzbuzz;
$fizzbuzz=make_fizzbuzz(make_fizzbuzz(sub {
  my ($n, $multiple)=@_;
  print $n if !$multiple;
  print "\n";
  $fizzbuzz->($n+1) if $n<1000;
}, 5, 'buzz'), 3, 'fizz');
$fizzbuzz->();
Dado que o código recursivamente cria uma recursão, parece natural começar pelo fim, então a primeira função passada é o caso especial e ela também é uma closure, porque precisa referenciar o ponto de partida.
Depois disso, podemos adicionar mais casos facilmente:
$fizzbuzz=make_fizzbuzz(make_fizzbuzz(make_fizzbuzz(make_fizzbuzz(sub {
  my ($n, $multiple)=@_;
  print $n if !$multiple;
  print "\n";
  $fizzbuzz->($n+1) if $n<1000;
}, 5, 'buzz'), 3, 'fizz'), 7, 'crackle'), 11, 'pop');
Bem elegante, na minha opinião.
 
 
