lunes, 5 de octubre de 2009

Calculadora Estadística: Toques finales

[English translation]
En el artículo anterior. dejamos pendiente lograr que el interpretador reconociera parámetros y fuera capaz de escribir cualquier valor de retorno de las funciones en Statistics::Descriptive.
Primero debemos definir como se separarán los comandos de los parámetros, y como se separarán los parámetros entre sí, y la manera más fácil es hacerlo como el shell, es decir usando espacios en blanco para ambos, así una vez que se obtiene una línea de comandos:
34     $command =~ s/^\s+//; $command =~ s/\s+$//;
35     my @args = split /\s+/, $command;
36     my $oper = looks_like_number( $args[0] ) ? "add_data" : shift @args;
se eliminan los espacios al principio y al final (34), se separan todos los elementos separados por uno o más blancos (35), y se obtiene la operación a realizar (36) que en general es el primer elemento, excepto en el caso de números en que la operación es "add_data". Luego de estas operaciones tenemos la operación a realizar en $oper y sus argumentos en @args, por lo que solamente resta aplicarlos:

38         when (%FUNCS)               { apply( $oper, @args ) }
La rutina a cargo de la aplicación de la operación debe obtener los argumentos (26), evaluar la operación en contexto lista (27), ¿por qué en contexto lista?, para permitir operaciones como "percentile" que produce múltiples valores.
Una vez obtenido el valor calculado, hay que verificar si vale la pena imprimirlo, así que retornamos si @result está vacío (28), o si tiene un solo elemento pero no esta definido o es una cadena vacia (29).
Para desplegar valores complejos utilizaré el formato YAML, porque es muy legible y tengo a disposición el módulo YAML del CPAN.
Así que dependiendo del número de elementos en @result convertiré el primer escalar o todo el arreglo en un texto en YAML antes de imprimirlo (30).
La calculadora de consola finalmente luce así:
 1 #!/usr/bin/perl
 2 
 3 use Modern::Perl;
 4 use Scalar::Util qw( looks_like_number );
 5 use Statistics::Descriptive;
 6 use Pod::Perldoc;
 7 use Term::ReadLine;
 8 use YAML;
 9 
10 my $term = new Term::ReadLine 'Statistic Calculator';
11 
12 my %FUNCS = map { $_ => 1 } qw( sum mean count variance standard_deviation
13     min mindex max maxdex sample_range median harmonic_mean geometric_mean
14     mode trimmed_mean clear add_data percentile quantile least_squares_fit
15     frequency_distribution_ref frequency_distribution);
16 
17 my @COMMANDS = qw( exit quit help man );
18 
19 sub help { say "Comandos: " . join( ", ", sort @COMMANDS, keys %FUNCS ) }
20 
21 sub man { Pod::Perldoc->new( args => \@_ )->process }
22 
23 my $s = Statistics::Descriptive::Full->new();
24 
25 sub apply {
26     my ( $oper, @args ) = @_;
27     my @result = $s->$oper(@args);
28     return unless @result;
29     return unless @result > 1 or (defined $result[0] and $result[0] ne "");
30     say YAML::Dump( @result == 1 ? $result[0] : \@result );
31 }
32 
33 while ( defined( my $command = $term->readline("Listo> ") ) ) {
34     $command =~ s/^\s+//; $command =~ s/\s+$//;
35     my @args = split( /\s+/, $command ) or next;
36     my $oper = looks_like_number( $args[0] ) ? "add_data" : shift @args;
37     given ($oper) {
38         when (%FUNCS)               { apply( $oper, @args ) }
39         when ("man")                { man "Statistics::Descriptive" }
40         when ( [ "exit", "quit" ] ) {last}
41         when ("help")               {help}
42         default                     { say "Error: tipee 'help' para ayuda" };
43     }
44 }
Después de está serie de artículos, espero que puedas apreciar, lo rápido que se puede trabajar en Perl, usando los mecanismos que ofrece el lenguaje y la inmensa cantidad de herramientas disponibles en el CPAN.
En futuras ocasiones utilizaré este ejemplo para ilustrar otras técnicas como la programación web, la orientación a objetos de Perl y por supuesto más módulos del CPAN.

No hay comentarios:

Publicar un comentario