Práctica: Area de un Círculo

Escriba un programa que solicite de la entrada un radio de una circunferencia e imprima el área del correspondiente círculo ( $ S = \pi \times r^2$). El proceso debe repetirse hasta que el radio contiene una cadena no numérica. Compruebe además que el radio no es negativo.

  1. Escriba la documentación de uso del programa (véase perldoc perlpod).

  2. Encuentre los errores por medio del depurador (véase perldebtut).

  3. Utilice subversion. Cree un repositorio. Añada al repositorio un proyecto practicas_lhp conteniendo la jerarquia

    practicas_lhp
         |
         |-trunk
         |   |
         |   `-area_de_un_circulo 
         |            | 
         |            |- area_de_un_circulo.pl
         |            |- MANIFEST
         |            |- Makefile
         |            |- test.input
         |            `- test.expected
         |-branches
         |
         `-tags
    

  4. Declare todas sus variables. Asegúrese de que usa strict.

    Declare las variable mediante la palabra reservada my:

    my $a =4;
    {
      my ($b, $c) = ("a", 9.2);
      $a = $b + 2*$c;
    }
    print $a;
    
    Una variable declarada con my tiene por ámbito el del bloque en que fué declarada o el fichero si esta fuera de bloques.

  5. Use perlcritic

  6. Constantes: Para definir la constante $ \pi = 4 \times atan(1) = 4 \times \pi /4$ use el módulo constant:
    pl@nereida:~/src/perl/uploadlab/Education-Labs/lib/Education$ perl -wde 0
    main::(-e:1):   0
      DB<1> use constant PI    => 4 * atan2(1, 1) 
      DB<2> print PI."\n"
    3.14159265358979
    

  7. Para obtener información sobre atan2 use perldoc -f atan2:

    lhp@nereida:~/Lperl/src$ perldoc -f atan2 
           atan2 Y,X
                   Returns the arctangent of Y/X in the range -PI to PI.
                   For the tangent operation, you may use the "Math::Trig::tan" function, 
                   or use the familiar relation:
    
                       sub tan { sin($_[0]) / cos($_[0])  }
    
                   Note that atan2(0, 0) is not well-defined.
    

  8. Compruebe el comportamiento de su programa contra entradas
    1. Cero, muy cerca de cero
    2. Negativas
    3. Cadenas de caracteres
    4. Cadenas de caracteres que contienen números, p. ej. "one 1.0 two 2.0"
    5. Diferentes formatos de flotante: 1e2, 1.0e-1, etc.

  9. Controle la aparición de interrupciones de teclado estableciendo un manejador de la señal INT

Casiano Rodríguez León
2010-03-03
> indica el número máximo de campos en los que se divide.

 
lhp@nereida:~/projects/perl/src$ perl -wde 0
main::(-e:1):   0
  DB<1> $a = 'a:b:c:d:e'
  DB<2> @a = split /:/, $a
  DB<3> x @a
0  'a'
1  'b'
2  'c'
3  'd'
4  'e'
  DB<4> @a = split /:/, $a, 3
  DB<5> x @a
0  'a'
1  'b'
2  'c:d:e'
  DB<6> $a = 'a:b:c:d::'
  DB<7> @a = split /:/, $a
  DB<8> x @a # Los nulos finales se suprimen
0  'a'
1  'b'
2  'c'
3  'd'
  DB<9> @a = split /:/, $a, -1 
  DB<10> x @a # No si LIMIT es negativo
0  'a'
1  'b'
2  'c'
3  'd'
4  ''
5  ''
Observe que en split el primer parámetro es una expresión regular mientras que en join es un carácter.

La función sort

El operador sort toma una lista de valores y los ordena según el alfabeto ASCII. Por ejemplo:

@rocks = qw/ bedrocks slate rubble granite /;
@sorted = sort (@rocks); # bedrocks granite rubble slate
El operador sort de Perl utiliza los operadores de cadenas por defecto:

:~/perl/src> perl -de 0
main::(-e:1):   0
  DB<1> print "a" == "b"
1
  DB<2> @x = sort (10, 2);
  DB<3> p "@x"
10 2

El Bloque de Comparación

La función sort admite como primer argumento un bloque que determina la función de comparación. Dicho bloque depende de dos variables ''especiales'' a y b .

El valor retornado por un bloque es el valor asociado con la última sentencia del bloque. En este caso sort espera que el bloque devuelva -1, 0 ó 1. Dicho valor es utilizado como elemento de comparación. Por ejemplo:

lhp@nereida:~/Lperl/src$ perl -dwe 0
main::(-e:1):   0
  DB<1> @a = (4, 7, 9, 12, -1)
  DB<2> p 4 <=> 7
-1
  DB<3> p 9 <=> 2
1
  DB<4> p 13 <=> 12+1
0
  DB<5> @a = sort { $a <=> $b } @a;
  DB<6> p "@a"
-1 4 7 9 12
  DB<7> @a = sort { $b <=> $a } @a;
  DB<8> p "@a"
12 9 7 4 -1

Ejemplo de Ordenación

El siguiente ejemplo ordena los usuarios de un sistema unix atendiendo a su uid:

lhp@nereida:~/projects/perl/src$ cat -n sortperuid.pl
 1  #!/usr/bin/perl -w
 2  use strict;
 3  my @user =  grep { $_ !~ /^#/ } `cat /etc/passwd`;
 4  my (@name, @uid, $x);
 5
 6  for (my $i=0; $i < @user; $i++) {
 7    ($name[$i], $x, $uid[$i]) = split ':', $user[$i];
 8  }
 9
10  @name = @name[
11    sort {$uid[$a] <=> $uid[$b]} 0..$#name
12  ];
13
14  local $" = "\n";
15  print "@name\n";
En la línea 3 se obtiene en @user la lísta de líneas no comentadas en /etc/passwd. en las líneas 6-8 se inicializan los arrays @name y @uid a los nombres (login) y uid de los usuarios (campos primero y tercero de /etc/passwd). Las líneas 10-12 ordenan primero la lista 0..$#name de acuerdo con el valor de uid. El nuevo conjunto ordenado de índices es utilizado para reindexar el array name.

El operador sort en un contexto escalar devuelve undef.

Los Módulos List::Util y List::MoreUtils

El módulo List::Util provee un conjunto de funciones para el manejo de listas. Veamos algunos ejemplos de uso de List::Util :

  DB<1> use List::Util qw(first max maxstr min minstr reduce shuffle sum)
  DB<2> @a = map { int(rand 20) } 1..5
  DB<3> x @a
0  8
1  9
2  4
3  16
4  5
  DB<4> x min @a
0  4
  DB<5> x max @a
0  16
  DB<6>x first { $_ > 8 } @a
0  9
  DB<7> x sum @a
0  42
  DB<8> x shuffle @a
0  8
1  5
2  16
3  4
4  9
  DB<9> x reduce { $a." $b" } @a
0  '8 9 4 16 5'

Existe también un módulo List::MoreUtils que provee mas funciones para el manejo de listas. He aqui un fragmento de la sección SYNOPSIS de la documentación:

          use List::MoreUtils qw(any all none notall true false firstidx first_index
                                  lastidx last_index insert_after insert_after_string
                                  apply after after_incl before before_incl indexes
                                  firstval first_value lastval last_value each_array
                                  each_arrayref pairwise natatime mesh zip uniq minmax);

Veamos algunos ejemplos de uso de List::MoreUtils :

lhp@nereida:~/Lperl/src/XSUB/h2xsexample/Coord/script$ perl -de 0
main::(-e:1):   0
  DB<1> use List::MoreUtils qw(:all) # Importar todas las funciones
  DB<2> @a = (1..8,-2,-3)
  DB<4> print "@a" if any { $_ > 0 } @a
1 2 3 4 5 6 7 8 -2 -3
  DB<5> print "@a" if all { $_ > 0 } @a

  DB<6> print (false {$_ > 0} @a),"\n" # Número de elementos para los que es falsa la condición
2
  DB<7> print (firstidx {$_ < 0} @a),"\n"
8
  DB<8> @a = (1..3,2..5,3..6)
  DB<9> x uniq(@a) # Array con los elementos distintos
0  1
1  2
2  3
3  4
4  5
5  6
  DB<8> @a = 1..5; @b = 'a'..'e'; @c = 10..14
  DB<9> x mesh @a, @b, @c # Mezcla los 3 arrays
0  1
1  'a'
2  10
3  2
4  'b'
5  11
6  3
7  'c'
8  12
9  4
10  'd'
11  13
12  5
13  'e'
14  14

El Array Especial @ARGV

El array especial @ARGV contiene la lista de argumentos del programa.

El array @ARGV es usado como array por defecto cuando se realiza una operación de arrays dentro del programa principal:

nereida:~/etc> perl -wde 0 one two three
main::(-e:1):   0
  DB<1> p "@ARGV"
one two three
  DB<2> p $^X # La variable mágica $^X tiene el camino al intérprete Perl utilizado
/usr/bin/perl
  DB<3> $a = shift # No se especifica el arrray: es @ARGV
  DB<4> x $a
0  'one'
  DB<5> $b = pop
  DB<6> x $b
0  'three'
  DB<7> x $^O # La variable $^O contiene el nombre del sistema operativo.
0  'linux'
  DB<8> x $0  # La variable mágica $0 contiene el nombre del programa
0  '-e'

Allanamiento de las listas

En contra de lo que quizá algunos podrían esperar, una lista que contiene a otra lista:

@virtues = ("faith", "hope", ("love", "charity"));

no produce una jerarquía de listas, sino que la lista es aplanada y es lo mismo que si nunca se hubieran puesto los paréntesis. Esto es, es equivalente a:

@virtues = ("faith", "hope", "love", "charity");



Subsecciones
Casiano Rodríguez León
2011-02-09