1. Мы передаем в функцию не сам массив, а ссылку на него \@arr3 (со слэшем вначале) - это чтобы память не засорять и мало-ли потом нужно будет ещё какие-нить параметры добавить... Соответственно если внутри функции в переменной $arr ссылка на массив, а нам нужен он сам, то достаем его так: {$arr}. Элемент массива можно из ссылки выташить так: $arr->[$i].
2. Так как в сортируемом массиве могут оказаться одинаковые элементы, то значением в хэше для этого элемента должен быть не один индекс, а несколько, иначе мы потеряем все одинаковые элементы. Тут можно было либо просто в строке эти индексы перечислить, а потом разбить эту строку:

Код:
foreach my $i(0..$#{$arr}) {
$hash{$arr->[$i]} .= $i.",";
}
my @result = ();
foreach my $sorted(sort @{$arr}) {
push @result, split (",", $hash{$sorted});
$hash{$sorted} = "";
}
Либо как сделал я - Элементами кэша являются массивы, а не строки, что позволяет не делать потом split. Т.е. мы сначала объявляем элемент хэша как массив: @{$hash{$arr->[$i]}} = () а потом добавляем в этот массив индексы.
Да, только сейчас заметил, что при генерации результата лучше сделать так:

Код:
my @result = ();
foreach my $sorted(sort keys %hash) {
push @result, @{$hash{$sorted}};
}
Тогда не будем повторно пробегать по одинаковым элементам исходного массива
