Here are a couple of minor optimisations:
1) In the transform sub you copy the contents of the @words array unnecessarily. Change:
50 my @words = @{+shift};
72 foreach my $word (@words) {
95 foreach my $word (@words) {
To:
50 my $words = shift;
72 foreach my $word (@$words) {
95 foreach my $word (@$words) {
2) The four argument form of substr is more efficient then assigning to the three argument form of substr. Change:
118 substr((my $pat = $word), $i, 1) = '.';
To:
118 substr my $pat = $word, $i, 1, '.';
HTH