Referències i Subrutines

350 views

Published on

Published in: Education, Business, Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
350
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Referències i Subrutines

  1. 1. Referències & Subrutines Jordi Delgado Curs BCN Perl Mongers 5 Novembre 2011 remember, remember the fifth of November...sábado 12 de noviembre de 2011
  2. 2. Els Array i els Hash poden contenir només escalars... Com podem construir estructures de dades complexes?sábado 12 de noviembre de 2011
  3. 3. doncs com sempre... amb punters! referències = punterssábado 12 de noviembre de 2011
  4. 4. Operador referència: Context escalar: referència Context llista: llista de referències Una referència és un escalarsábado 12 de noviembre de 2011
  5. 5. exemples: my $nom = ‘anonymous’; my $nom_ref = $nom; # referència a escalar my @llista = qw< anon1 anon2 anon3 >; my $llista_ref = @llista # referència a array my $aliased_llista = $llista_ref; my %diccionari = ( op1 => ‘fail’, op2 => ‘success’, op3 => ‘unknown’, op4 => ‘unknown’ ); my $diccionari_ref = %diccionari; # referència a hash my $aliased_diccionari = $diccionari_ref;sábado 12 de noviembre de 2011
  6. 6. Des-referenciar: afegir un sigil més que dependrà d’allò referenciat, utilitzant claus envoltant la referència my @llista = qw< anon1 anon2 anon3 >; my $llista_ref = @llista # referència a array my $aliased_llista = $llista_ref; print "@{ $llista_ref } n"; my %diccionari = ( op1 => ‘fail’, op2 => ‘success’, op3 => ‘unknown’, op4 => ‘unknown’ ); my $diccionari_ref = %diccionari; # referència a hash my $aliased_diccionari = $diccionari_ref; print keys %{ $diccionari_ref } , "n"; print values %{ $diccionari_ref } , "n";sábado 12 de noviembre de 2011
  7. 7. Però, si el que volem des-referenciar és només una variable escalar no fan falta les claus {} @{ $llista_ref } = @$llista_ref ${ $llista_ref }[0] = $$llista_ref[0] print $$llista_ref[$_], "n" foreach (0..$#$llista_ref) %{ $diccionari_ref } = %$diccionari_ref ${ $diccionari_ref }{op2} = $$diccionari_ref{op2} print $$diccionari_ref{$_}, "n" foreach keys %$diccionari_ref; farem servir les claus {} només per desambiguar, quan calguisábado 12 de noviembre de 2011
  8. 8. Ara ja podem construir estructures de dades complexes: my %ops_from_anon1 = ( op1 => ‘fail’, op2 => ‘success’, op3 => ‘unknown’, ); my %ops_from_anon2 = ( op4 => unknown, ); my @primer_grup_ops = (anon1, %ops_from_anon1); my @segon_grup_ops = (anon2, %ops_from_anon2); my @ops = (@primer_grup_ops, @segon_grup_ops); foreach my $op (@ops) { print "Origen: $$op[0] n"; print "t Nom de la op: $_, estat: ${ $$op[1] }{$_} n" foreach keys %{ $$op[1] }; }sábado 12 de noviembre de 2011
  9. 9. Notació alternativa: the dereferencing arrow my %ops_from_anon1 = ( op1 => ‘fail’, op2 => ‘success’, op3 => ‘unknown’, ); my %ops_from_anon2 = ( op4 => unknown, ); my @primer_grup_ops = (anon1, %ops_from_anon1); my @segon_grup_ops = (anon2, %ops_from_anon2); my @ops = (@primer_grup_ops, @segon_grup_ops); foreach my $op (@ops) { print "Origen: $op->[0] n"; print "t Nom de la op: $_, estat: $op->[1]->{$_} n" foreach keys %{$op->[1]}; }sábado 12 de noviembre de 2011
  10. 10. Array i Hash anònims Array: [ ... ] Hash: { ... } my @ops = ( [anon1, { op1 => fail, ! ! op2 => success, ! ! op3 => unknown, }], [anon2, { op4 => unknown, }] ); foreach my $op (@ops) { print "Origen: $op->[0] n"; print "t Nom de la op: $_, estat: $op->[1]->{$_} n" foreach keys %{$op->[1]}; }sábado 12 de noviembre de 2011
  11. 11. Però s’ha d’anar amb una mica de compte: my @llista = qw< anon1 anon2 anon3 >; my $llista1_ref = @llista; my $llista2_ref = @llista; push @llista, anon4;...tant @$llista1_ref com @$llista2_ref tenen un servidor nou, però... my @llista = qw< anon1 anon2 anon3 >; my $llista1_ref = [ @llista ]; my $llista2_ref = [ @llista ]; push @llista, anon4;...ni @$llista1_ref ni @$llista2_ref tenen cap servidor nou afegitsábado 12 de noviembre de 2011
  12. 12. Autovivificació La idea és que si des-referenciem una variable escalar -que conté undef- com si fos una referència a un array, se li assignarà una referència a un array anònim buit i es procedirà amb l’execució del codi. El mateix passarà amb un hash, si ens trobem una variable de valor undef que es des-referenciada com si fos una referència a un hash, s’assigna un hash anònim buit i l’execució continuarà.sábado 12 de noviembre de 2011
  13. 13. Autovivificació my $ops; $ops->[0]->[0] = anon1; $ops->[1]->[0] = anon2; $ops->[0]->[1]->{op1} = fail; $ops->[0]->[1]->{op2} = success; $ops->[0]->[1]->{op3} = unknown; $ops->[1]->[1]->{op4} = unknown; foreach my $op (@$ops) { print "Origen: $op->[0] n"; print "t Nom de la op: $_, estat: $op->[1]->{$_} n" foreach keys %{$op->[1]}; }sábado 12 de noviembre de 2011
  14. 14. if the arrow ends up between "subscripty kinds of things" such as square brackets, we can also drop the arrow. my $ops; $ops->[0][0] = anon1; $ops->[1][0] = anon2; $ops->[0][1]{op1} = fail; $ops->[0][1]{op2} = success; $ops->[0][1]{op3} = unknown; $ops->[1][1]{op4} = unknown; foreach my $op (@$ops) { print "Origen: $op->[0] n"; print "t Nom de la op: $_, estat: $op->[1]{$_} n" foreach keys %{$op->[1]}; }sábado 12 de noviembre de 2011
  15. 15. Problemes: Aliasing (as usual) Comptatge de referències (no garbage collection)sábado 12 de noviembre de 2011
  16. 16. SUB-RU-TI-NES (no funcions, ni procediments, ni mètodes, ni...)sábado 12 de noviembre de 2011
  17. 17. SUB-RU-TI-NES (no funcions, ni procediments, ni mètodes, ni...) Spock: Cadet Kirk, you somehow managed to install and activate a subroutine in the programming code, thereby changing the conditions of the test. James T. Kirk: Your point being? Admiral Richard Barnett: In academic vernacular, you cheated. Star Trek (2009)sábado 12 de noviembre de 2011
  18. 18. SUB-RU-TI-NES (no funcions, ni procediments, ni mètodes, ni...) Spock: Cadet Kirk, you somehow managed to install and activate a subroutine in the programming code, thereby changing the conditions of the test. James T. Kirk: Your point being? Admiral Richard Barnett: In academic vernacular, you cheated. Star Trek (2009) Kim: Shes not a member of the crew. Shes a character on the holodeck. Tuvok: Youre in love with a computer subroutine? Kim: Thats the problem. Tuvok: Interesting. Star Trek Voyager, ‘Alter Ego’ S03E14 (1997)sábado 12 de noviembre de 2011
  19. 19. SUB-RU-TI-NES (no funcions, ni procediments, ni mètodes, ni...) Spock: Cadet Kirk, you somehow managed to install and activate a subroutine in the programming code, thereby changing the conditions of the test. James T. Kirk: Your point being? Admiral Richard Barnett: In academic vernacular, you cheated. Star Trek (2009) Kim: Shes not a member of the crew. Shes a character on the holodeck. Tuvok: Youre in love with a computer subroutine? Kim: Thats the problem. Tuvok: Interesting. Star Trek Voyager, ‘Alter Ego’ S03E14 (1997) Lt. Cmdr. Data: You are much more than that, Jenna. I have written a subroutine specifically for you - a program within the program. I have devoted a considerable share of my internal resources to its development. Lt. Jenna DSora: Data... thats the nicest thing anybodys ever said to me. Star Trek The Next Generation, ‘In Theory’ S04E25 (1991)sábado 12 de noviembre de 2011
  20. 20. Subrutines Declaració: sub nom_de_la_subrutina { . . . } Invocació: nom_de_la_subrutina ( ... ) # de vegades podem prescindir dels parèntesi, però millor # que no (som moderns :-)) # # de vegades cal posar un ampersand (&) davant del nom, però # si no anomenem cap subrutina igual que una subrutina de perl # no ha d’haver cap problemasábado 12 de noviembre de 2011
  21. 21. Subrutines Pas de paràmetres: nom_de_la_subrutina ( ... ) # en el moment de la crida, tots els paràmetres es disposen # en un array d’escalars (flattening) # que es veu des de dins de la subrutina com l’array @_ exemple: # hanoi(N, start, end, extra) # Solve Tower of Hanoi problem for a tower of N disks, # of which the largest is disk #N. Move the entire tower from # peg start to peg end, using peg extra as a work space sub hanoi { my ($n, $start, $end, $extra) = @_; if ($n == 1) { print "Move disk #1 from $start to $end.n"; # Step 1 } else { hanoi($n-1, $start, $extra, $end); # Step 2 print "Move disk #$n from $start to $end.n"; # Step 3 hanoi($n-1, $extra, $end, $start); # Step 4 } } (from Higher-Order Perl by Mark Dominus, published by Morgan Kaufmann Publishers, Copyright 2005 by Elsevier Inc)sábado 12 de noviembre de 2011
  22. 22. Pas de paràmetres: nom_de_la_subrutina ( ... ) # pas de paràmetres per valor? per referència? # En realitat @_ conté alias dels paràmetres originals, així, # si modifiquem $_[i] estarem modificant el paràmetre i-èssim # real. En canvi, en assignar-los, els paràmetres reals es # copien exemple: sub modifica_nom1 { sub modifica_nom2 { $_[0] = reverse($_[0]); my $temp = shift; } $temp = reverse $temp; } my $nom = Jordi; my $nom = Jordi; modifica_nom1( $nom ); modifica_nom2( $nom ); print $nom, “n”; print $nom, “n”; idroJ Jordisábado 12 de noviembre de 2011
  23. 23. Accés als paràmetres: sub hanoi { my ($n, $start, $end, $extra) = @_; if ($n == 1) { print "Move disk #1 from $start to $end.n"; # Step 1 } else ( . . . ) The dominant practice seems to be to use shift only when your function must access a single parameter and list assignment when accessing multiple parameters. Què retorna una subrutina? Allò que s’ha calculat tot just abans d’acabar o bé allò que és explícitament retornat amb returnsábado 12 de noviembre de 2011
  24. 24. Lexicals: El my que hem vist davant de les variables quan les feiem servir per primera vegada li diu a perl que aquelles variables són locals al bloc més proper que conté el my... ... i això és perque ... totes les variables són globals, per defecte.sábado 12 de noviembre de 2011
  25. 25. * Retorn de valors no escalars: No hi ha cap diferència. Es poden retornar elements que no siguin escalars exactament de la mateixa manera. També podem retornar referències. * Context? Una subrutina pot conèixer el context en el que ha estat cridada gràcies a wantarray: wantarray() -> undef si el context és void wantarray() -> true si el context és llista wantarray() -> false si el context és escalarsábado 12 de noviembre de 2011
  26. 26. Referències a subrutines (coderefs): my $ref = &nom_de_subrutina; # ampersand obligatori! també, només volem el nom ... $ref->(p1,p2,...) # equivalent a nom_de_subrutina(p1,p2,...) # fixem-nos en la dereferencing arrow A partir del moment en que puc manipular referències a funcions, ja puc emmagatzemar-les, retornar-les, passar-les com a paràmetre... són ciutadans de primera classe (en realitat no, però si).sábado 12 de noviembre de 2011
  27. 27. Subrutines anònimes my $ref_a_subrutina = sub { . . . } # el cos de la subrutina no té res d’especial # el resultat és una referència a una subrutina Closures (tancaments lexics): sub simple_demo { my $privatecounter = 0; return sub { $privatecounter++ }; } my $demo1 = simple_demo; my $demo2 = simple_demo; foreach (0..5) { print $demo1->(), “n”; print $demo2->(), “n”; }sábado 12 de noviembre de 2011
  28. 28. sábado 12 de noviembre de 2011
  29. 29. Problema: Memoització Fer una funció memoize on donada una ref. a una funció f, retorni una ref. a una funció g que calculi el mateix que f, però emmagatzemi allò que calcula, de manera que no ho calculi explícitament mai dues vegades. Solució: sub memoize { my ($func) = @_; my %cache; return sub { my $key = join ‘,’ , @_; $cache{$key} = $func->(@_) unless exists $cache{$key}; return $cache{$key}; }; }sábado 12 de noviembre de 2011
  30. 30. Problema: map Si llista és (l1, l2, l3,...) fer una funció map tal que map (&f, llista) -> (f(l1), f(l2), f(l3),...) Solució: sub map { my $func = shift; my @result = (); foreach (@_) { push @result, $func->($_); } return @result; }sábado 12 de noviembre de 2011
  31. 31. Problema: grep Si llista és (l1, l2, l3,...) i f és una funció amb resultat booleà (diguem, {0,1}) fer una funció grep tal que grep (&f, llista) -> (li, lj, lk,...) on els li, lj, lk,... són aquells elements de la llista tals que quan se’ls aplica f el resultat és 1. Solució: sub grep { my $func = shift; my @result = (); foreach (@_) { push(@result, $_) if $func->($_); } return @result; }sábado 12 de noviembre de 2011
  32. 32. Problema: inject Si llista és (l1, l2, l3,...) fer una funció inject tal que inject (&f, escalar, llista) -> f(... f(f(f(escalar,l1),l2),l3) ...) Solució: sub inject { my $func = shift; my $escalar = shift; my $result = $escalar; foreach (@_) { $result = $func->($result,$_); } return $result; }sábado 12 de noviembre de 2011

×