perl - sintaxis - php lenguaje de programacion
¿Cuáles son algunas características o usos elegantes de Perl? (14)
¿Qué? Perl hermosa? Elegant ? Él debe estar bromeando!
Es cierto, hay algunos Perl feos por ahí. Y por algunos, me refiero a muchos. Todos lo hemos visto.
Bueno, es una sopa de símbolos. ¿No es así?
Sí, hay símbolos. Al igual que ''matemática'' tiene ''símbolos''. Es solo que los programadores estamos más familiarizados con los símbolos matemáticos estándar. Crecimos para aceptar los símbolos de nuestros idiomas maternos, ya sea ASM, C o Pascal. Perl simplemente decidió tener algunos más.
Bueno, creo que deberíamos deshacernos de todos los símbolos innecesarios. Hace que el código se vea mejor.
El lenguaje para hacerlo ya existe. Se llama Lisp. (y pronto, perl 6 )
De acuerdo, chico inteligente. La verdad es que ya puedo inventar mis propios símbolos. Se llaman funciones y métodos. Además, no queremos reinventar APL .
¡Oh, falso alter ego, eres muy gracioso! Es realmente cierto, Perl puede ser bastante hermoso. También puede ser bastante feo. Con Perl, TIMTOWTDI .
Entonces, ¿cuáles son tus partes elegantes favoritas de código Perl?
¿Tiene una lista de archivos que el usuario quiere que su programa procese? ¿No desea procesar accidentalmente un programa, carpeta o archivo inexistente? Prueba esto:
@files = grep { -T } @files;
Y, como magia, eliminaste todas las entradas inapropiadas. No quiero ignorarlos en silencio? Agregue esta línea antes de la última:
warn "Not a file: $_" foreach grep { !-T } @files;
Imprime un bonito mensaje de advertencia para cada archivo que no puede procesar a error estándar. Lo mismo sin usar grep
se vería así:
my @good;
foreach(@files) {
if(-T) {
push @good, $_;
} else {
warn "Not a file: $_";
}
}
grep
(y el map
) se pueden usar para hacer que el código sea más corto y, al mismo tiempo, mantenerlo muy legible.
Además del amor por el map
y grep
, podemos escribir un analizador de línea de comandos simple.
my %opts = map { $_ => 1 } grep { /^-/ } @ARGV;
Si queremos, podemos establecer cada indicador para su índice en @ARGV:
my %opts = map { $ARGV[$_] => $_ } grep { $ARGV[$_] =~ /^-/ } 0 .. $#ARGV;
De esa forma, si una bandera tiene un argumento, podemos obtener el argumento de esta manera:
if( defined( $opts{-e} ) ) {
my $arg = $ARGV[ $opts{-e} ];
# do -e stuff for $arg
}
Por supuesto, algunas personas llorarán diciendo que estamos reinventando la rueda y deberíamos usar getopt o alguna variante de la misma, pero honestamente, esta fue una rueda bastante fácil de reinventar. Además, no me gusta Getopt.
Si no le gusta el tiempo que algunas de esas líneas son, siempre puede usar variables intermedias o solo saltos de línea convenientes (hey, fanáticos de Python? ¿Oye eso? ¡Podemos poner una línea de código en dos líneas y todavía funciona! ) para que se vea mejor:
my %opts = map { $ARGV[$_] => $_ }
grep { $ARGV[$_] =~ /^-/ } 0 .. $#ARGV;
Clases de tres líneas con constructores, getter / setters y validación de tipo:
{
package Point;
use Moose;
has [''x'', ''y''] => (isa => ''Num'', is => ''rw'');
}
package main;
my $point = Point->new( x => ''8'', y => ''9'' );
$point->x(25);
El constructo "o morir":
open my $fh, "<", $filename
or die "could not open $filename: $!";
El uso de qr // para crear gramáticas:
#!/usr/local/ActivePerl-5.10/bin/perl
use strict;
use warnings;
use feature '':5.10'';
my $non_zero = qr{[1-9]};
my $zero = qr{0};
my $decimal = qr{[.]};
my $digit = qr{$non_zero+ | $zero}x;
my $non_zero_natural = qr{$non_zero+ $digit*}x;
my $natural = qr{$non_zero_natural | $zero}x;
my $integer = qr{-? $non_zero_natural | $zero}x;
my $real = qr{$integer (?: $decimal $digit)?}x;
my %number_types = (
natural => qr/^$natural$/,
integer => qr/^$integer$/,
real => qr/^$real$/
);
for my $n (0, 3.14, -5, 300, "4ever", "-0", "1.2.3") {
my @types = grep { $n =~ $number_types{$_} } keys %number_types;
if (@types) {
say "$n is of type", @types == 1 ? " ": "s ", "@types";
} else {
say "$n is not a number";
}
}
Subrutinas anónimas utilizadas para factorizar código duplicado:
my $body = sub {
#some amount of work
};
$body->();
$body->() while $continue;
en lugar de
#some amount of work
while ($continue) {
#some amount of work again
}
Tablas de envío basadas en Hash:
my %dispatch = (
foo => /&foo,
bar => /&bar,
baz => /&baz
);
while (my $name = iterator()) {
die "$name not implemented" unless exists $dispatch{$name};
$dispatch{$name}->();
}
en lugar de
while (my $name = iterator()) {
if ($name eq "foo") {
foo();
} elsif ($name eq "bar") {
bar();
} elsif ($name eq "baz") {
baz();
} else {
die "$name not implemented";
}
}
Este mecanismo de análisis de archivos es compacto y fácil de personalizar (omita líneas en blanco, líneas de salto que comienzan con X, etc.).
open(H_CONFIG, "< $file_name") or die("Error opening file: $file_name! ($!)");
while (<H_CONFIG>)
{
chomp; # remove the trailing newline
next if $_ =~ /^/s*$/; # skip lines that are blank
next if $_ =~ /^/s*#/; # skip lines starting with comments
# do something with the line
}
Utilizo este tipo de constructo en diversas situaciones de compilación, donde necesito pre o post procesar los archivos de carga útil (S-records, etc.) o C-files o reunir información de directorio para una ''compilación inteligente''.
Estoy sorprendido de que nadie haya mencionado esto. Es una obra maestra en mi opinión:
#!/usr/bin/perl $==$''; $;||$.| $|;$_ =''*$ ( ^@(%_+&~~;# ~~/.~~ ;_);;.);;#) ;~~~~;_,.~~,.* +,./|~ ~;_);@-, .;.); ~ ~,./@@-__);@-);~~,.*+,. /|);;;~~@-~~~~;.~~,. /.);;.,./@~~@-;.;#~~@-;; ;;,.*+,./.);;#;./@,./ |~~~~;#-(@-__@-__&$#%^'';$__ =''`''&''&'';$___="````" |"$[`$["|''`%",'';$~=("$___$__-$[``$__"| "$___"| ("$___$__-$[.%")).("''`"|"''$["|"''#"). ''/.*?&([^&]*)&.*/$''.++$=.("/``"|"/$[`"|"/#''").(";`/[//`//`$__]//`;" |";$[/[//$[//`$__]//`;"|";#/[///$//.$__]//''").''@:=("@-","/.", "~~",";#",";;",";.",",.",");","()","*+","__","-(","/@",".%","/|", ";_");@:{@:}=$%..$#:;''.(''`''|"$["|''#'')."/(..)(..)/".("```"|"``$["| ''#("'').''(($:{$''.$=.''}<<''.(++$=+$=).'')|($:{$''.$=.''}))/''.("```;"| "``$[;"|"%''#;").("````''$__"|"%$[``"|"%&!,").${$[};`$~$__>&$=`;$_= ''*$(^@(%_+&@-__~~;#~~@-;.;;,.(),./.,./|,.-();;#~~@-);;;,.;_~~@-,./., ./@,./@~~@-);;;,.(),.;.~~@-,.,.,.;_,./@,.-();;#~~@-,.;_,./|~~@-,. ,.);););@-@-__~~;#~~@-,.,.,.;_);~~~~@-);;;,.(),.*+);;# ~~@-, ./|,.*+,.,.);;;);*+~~@-,.*+,.;;,.;.,./.~~@-,.,.,.;_) ;~~~ ~@-,.;;,.;.,./@,./.);*+,.;.,.;;@-__~~;#~~@-,.;;,.* +);; #);@-,./@,./.);*+~~@-~~.%~~.%~~@-;;__,. /.);;#@- __@- __ ~~;;);/@;#.%;#/.;#-(@-__~~;;;.;_ ;#.%~~~~ ;;() ,.;.,./@,. /@,.;_~~@- ););,.;_ );~~,./ @,. ;;;./@,./| ~~~~;#-(@- __,.,.,. ;_);~~~ ~@ -~~());; #);@-,./@, .*+);;; ~~@-~~ );~~);~~ *+~~@-);-( ~~@-@-_ _~~@- ~~@-);; #,./@,.;., .;.);@ -~~@-; #/.;#-( ~~@-@-__ ~~@-~~ @-);@ -);~~, .*+,./ |);;;~ ~@-~~ ;;;.; _~~@-@ -__);. %;#-( @-__@ -__~~;# ~~@-;; ;#,. ;_,.. %);@-,./@, .*+, ..%, .;.,./|) ;;;) ;;#~ ~@-,.*+,. ,.~~ @-); *+,.;_);;.~ ~);); ~~,.; .~~@-);~~,.;., ./.,.; ;,.*+ ,./|,.); ~~@- );;;,.( ),.*+); ;#~~/|@- __~~;#~~ $'';$;;
Los mecanógrafos más pobres como yo, que sufrimos calambres al presionar la tecla shift con demasiada frecuencia y tenemos un miedo casi irracional a utilizar un punto y coma, comenzamos a escribir nuestro código Perl en archivos formateados en python
. :)
p.ej
>>> k = 5
>>> reduce(lambda i,j: i*j, range(1,k+1),1)
120
>>> k = 0
>>> reduce(lambda i,j: i*j, range(1,k+1),1)
1
Me encanta Black Perl (enlace a la versión reescrita para compilar en Perl 5). Compila, pero hasta donde sé, en realidad no hace nada.
Eso es lo que obtienes para un idioma escrito por un lingüista desde una perspectiva pragmática en lugar de desde una perspectiva teórica.
Pasando de eso, puedes pensar en el Perl del que la gente se queja como pidgin Perl (perfectamente útil, pero no expresivo, y ten cuidado de tratar de expresar cualquier cosa compleja en él), y de lo que @pjf está hablando como "apropiado" "Perl, el lenguaje de Shakespeare, Hemingway, Hume y demás. [edit: err, aunque es más fácil de leer que Hume y menos fechado que Shakespeare.] [reedición y, con suerte, menos alcohólico que Hemingway]
Me sorprende que nadie haya mencionado la Transformación de Schwartz.
my @sorted =
map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [ $_, expensive_func($_) ] }
@elements;
Y en ausencia de un operador sorber,
my $file = do { local $/; readline $fh };
Mi característica favorita de Perl es que utiliza diferentes operadores para valores numéricos y valores de cadena.
my $string = 1 . 2;
my $number = "1" + "2";
my $unambiguous = 1 . "2";
Compare esto con otros lenguajes dinámicos como JavaScript, donde "+" se usa para concatenación y adición.
var string = "1" + "2";
var number = 1 + 2;
var ambiguous = 1 + "2";
O a lenguajes dinámicos como Python y Ruby que requieren coerción de tipo entre cadenas y valores numéricos.
string = "1" + "2"
number = 1 + 2
throws_exception = 1 + "2"
En mi opinión, Perl lo entiende bien y los demás idiomas lo malinterpretan.
Mis piezas favoritas de elegante código Perl no son necesariamente elegantes en absoluto. Son meta-elegantes , y te permiten deshacerte de todos esos malos hábitos en los que se han metido muchos desarrolladores de Perl. Me llevaría horas o días mostrarlos a todos con los detalles que merecen, pero a modo de lista breve incluyen:
- autobox , que convierte las primitivas de Perl en objetos de primera clase.
- autodie , que hace que los built-ins arrojen excepciones en caso de falla (eliminando la mayoría de las necesidades de la construcción
or die...
). Ver también mi blog y video autodie ). - Moose , que proporciona una forma elegante, extensible y correcta de escribir clases en Perl.
- MooseX::Declare , que proporciona asombrosidad sináptica cuando se usa Moose.
- Perl::Critic , su revisor de código personal, automático, extensible y conocedor. Ver también este Perl-tip .
- Devel::NYTProf , que me proporciona la información de perfiles más detallada y útil que he visto en cualquier lenguaje de programación. Ver también el Blog de Tim Bunce .
- PAR , Perl Archiver, por agrupar distribuciones e incluso convertir programas completos en archivos ejecutables independientes. Ver también este Perl-tip .
- Perl 5.10, que proporciona algunas impresionantes mejoras de expresiones regulares , smart-match , declaración de cambio , variables de estado definidas o .
- Padre , el único editor de Perl que integra las mejores partes del anterior, es multiplataforma, y es completamente gratuito y de código abierto.
Si eres demasiado perezoso para seguir enlaces, recientemente hice una charla en Linux.conf.au sobre la mayoría de los anteriores. Si te lo perdiste, hay un video en línea (ogg theora). Si eres demasiado perezoso para mirar videos, este año estoy haciendo una versión muy expandida de la charla como un tutorial en OSCON (titulado Perl right ).
Todo lo mejor,
Pablo
Perl facilita el uso de listas / hashes para implementar parámetros nombrados, que considero muy elegantes y una gran ayuda para el código de auto-documentación.
my $result = $obj->method(
flux_capacitance => 23,
general_state => ''confusion'',
attitude_flags => ATTITUDE_PLEASANT | ATTITUDE_HELPFUL,
);
Si tiene una lista de banderas separadas por comas y quiere una tabla de búsqueda para ellas, todo lo que tiene que hacer es:
my %lookup = map { $_ => 1 } split /,/, $flags;
Ahora puedes simplemente probar para qué banderas necesitas así:
if ( $lookup{FLAG} ) {
print "Ayup, got that flag!";
}
Un ejemplo favorito mío es la implementación de Perl de una calculadora factorial. En Perl 5, parece que sí:
use List::Util qw/reduce/;
sub factorial {
reduce { $a * $b } 1 .. $_[0];
}
Esto devuelve falso si el número es <= 1 o una cadena y un número si se pasa un número (redondeando hacia abajo si es una fracción).
Y esperando Perl 6, se ve así :
sub factorial {
[*] 1..$^x
}
Y también (desde el blog en el enlace de arriba) incluso puedes implementar esto como operador:
sub postfix:<!>(Int $x) {
[*] 1..($x || 1)
}
y luego úsala en tu código así:
my $fact5 = 5!;