Perl 6 - Histograma de Palavras
2015-09-14, por Alberto Simões ambs@cpan.org
Um exercício simples e típico, quando aprendemos uma nova linguagem de programação, é a escrita de um pequeno programa que, dado um ficheiro de texto, calcula quantas vezes cada palavra ocorre.
E para variar, vamos processar os parâmetros do programa à moda do Perl 5, olhando para o @ARGV que, em Perl 6, se chama @*ARGS. A razão daquele asterisco será detalhada noutra entrada.
my $filename = shift @*ARGS;
O passo seguinte é verificar se o nome do ficheiro foi, realmente, indicado e, em caso afirmativo, verificar se este é, ou não, um ficheiro:
if !$filename || $filename.IO !~~ :f {
die "filename not specified or not existent."
Para além da falta de parentesis a que nos começamos a habituar, a segunda parte da comparação apresenta algumas novidades. O ~~ é o smart match, um operador que, embora em estado experimental, já foi introduzido no Perl 5. A sua negação é, então, !~~. Ou seja, estamos a verificar se $filename.IO faz match a um :f. O método IO sobre o nome do ficheiro transforma-o num handler de ficheiro (com esse nome). O :f é uma propriedade equialente ao -f do Perl 5. Se tentarmos ler este código poderíamos dizer algo como *se o nome do ficheiro não estiver definido ou se o ficheiro não existir (e não for um ficheiro convencional), então o programa deverá terminar.
my $contents = slurp $filename;
for $contents ~~ m:global/\w+/ -> $word {
%histogram{$word.lc}++;
Segue-se a leitura do ficheiro, como um todo, para uma variável. Declara-se então a variável onde se armazenará o histograma.
O ciclo for inclui dois pormenores distintos. Em primeiro lugar a sintaxe do ciclo, que deixa de necessitar dos parentesis, e que troca a ordem da lista e da variável iteradora. Antes da seta -> devemos indicar a lista a ser percorrida, e de seguida, a variável que irá tomar o valor de cada um dos elementos da lista.
Para calcular a lista de palavras usamos expressões regulares típicas. Tal como no Perl 5, \w corresponde a um caracter alfanumérico, e portanto estamos à procura de todas as sequências de caracteres alfanuméricos. Por sua vez, o m:global tem duas partes: o m é o operador de matching, tal como já existia em Perl 5; o :global é um advérbio que indica que esse match deve ser global (tal como o /s do Perl 5). Então, $contents ~~ m:global/\w+/ retorna uma lista de todas as palavras encontradas.
Já o corpo do ciclo é o habitual, incrementando o número de ocorrências de cada palavra (depois de a ter transformado em minúsculas, com o método lc).
Só nos falta apresentar o resultado do histograma, ordenando as palavras por ocorrência, em ordem decrescente.
for %histogram.keys.sort({ %histogram{$^b} <=> %histogram{$^a}}) -> $key {
say "$key  ==>  %histogram{$key} occurrences";
Ora, para todas as chaves da variável %histogram ordenámo-las. Como não queremos ordenar as palavras por ordem alfabética, mas pelo número de ocorrências, temos de, tal como em Perl 5, indicar uma função de ordenação. Em Perl 6 as variáveis para a comparação são $^a e $^b, ao contrário das $a e $b do Perl 5. À parte desse detalhe, a sintaxe deverá ser fácil de compreender.
Executando o script sobre o ficheiro onde este texto está escrito, obtemos um resultado semelhante ao seguinte: