Closures in Perl

Dieses Thema im Forum "Ruby, php, Perl, Python ..." wurde erstellt von angelsfall, 15.12.2006.

  1. #1 angelsfall, 15.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Hi.

    Ich hab mir nun alles über Closures in Perl angelesen. Ich weiss, was sie sind, wie ich sie programmiere, welchen Sinn sie haben.

    Aber wann setzt man diese Teile ein?

    Sprich: Standardfälle bzw. Real-Life-Examples, nicht solche Pseudobeispiele, wie es sie überall gibt. Bisher hab ich die nämlich nicht gebraucht und irgendwie konnte ich bisher alles ohne sie lösen. Und man soll sie ja nicht zwingend verwenden. Es gibt zwar einige bessere Beispiele, aber wirklich klar ist mir die Benutzung noch nicht ...

    Any suggestions? :)

    Quellen:
    Programming Perl, O'Reilly
    Objektorientiert Programmieren mit Perl, Addison-Wesley
    http://www.stonehenge.com/merlyn/LinuxMag/col09.html
    http://www.perlmonks.org/?node_id=75792
     
  2. Anzeige

    Schau dir mal diesen Ratgeber an. Viele Antworten inkl. passender Shell-Befehle!
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  3. #2 hwj, 15.12.2006
    Zuletzt bearbeitet: 15.12.2006
    hwj

    hwj Doppel-As

    Dabei seit:
    23.06.2006
    Beiträge:
    131
    Zustimmungen:
    0
    Ort:
    Bei Buxtehude
    Hm, noch keiner seinen Senf dazugegeben, das Thema ist doch recht interessant ...:D

    Ich benutze die recht häufig, meistens beim programmieren von CGI-Programmen unter Apache (mod_perl). Hauptgrund ist für mich die bessere Übersichtlichkeit. Wenn ich z.B. in einer Schleife was aus der Datenbank lese und unterschiedliche Ausgaben für verschiedene Nutzer der Seite mache, dann schaut das z.B. wie folgt aus:
    Code:
    ...
        my $display_user = sub {
            my ($user_id, $username) = @_;
            return $username;
        };
    
        if ($param->isADMIN()) {
            my $orig = $display_user;
            $display_user = sub {
                # Admin gets link to user profile ...
                return $cgi->url({-href=>'/cgi-bin/foo.pl?user_id=' . $user_id}, &$orig(@_));
            };
        }
    
        if ($param->isGUEST()) {
            $display_user = sub {
                return ''; # hide username output for guests ...
            };
        }
    
        ...
        my $ret = '';
        while (($user_id, $username) = $db->fetchrow_array()) {
            $ret .= &$display_user($user_id, $username);
        }
    
        ...
    
    (Mal so eben aus dem Kopf hinprogrammiert, muß nicht fehlerfrei sein).

    Ich erinnere mich auch mal an ein Programm wo ich unterschiedliche Berechnungsmethoden mit zwei Arrays brauchte, das drumherum war gleich, nur die Berechnung war unterschiedlich:
    Code:
    ...
        my $calc = undef;
    
        if ($arg == 1) {
            $calc = sub { my ($a, $b) = @_; return $a - $b; };
        }
        if ($arg == 2) {
            $calc = sub { my ($a, $b) = @_; return $b - $a; };
        }
        if ($arg == 3) {
            $calc = sub { my ($a, $b) = @_; return $a * $b; };
        }
        if (!defined($calc)) {
            $calc = sub { my ($a, $b) = @_; return $a + $b; };
        }
    
        my @arr1 = (....);
        my @arr2 = (....);
    
        my @result = berechnen(\@arr1, \@arr2, $calc);
    
        ....
    
    Sicher kann man das anders lösen, ist halt Geschmackssache. Wenn man sich erstmal dran gewöht hat, mag man sie nicht mehr missen.

    Heiko
     
  4. #3 Xanti, 15.12.2006
    Zuletzt bearbeitet: 15.12.2006
    Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    So mein Senf auch noch dazu: ;)

    Neben dynamischen Funktionsnamen kann man closures auch für den Fall verwenden, wenn man Funktionen innerhalb von Funktionen definieren will, die Ihre Variablen teilen:

    Code:
    #!/usr/bin/perl -w                                                                                       
    
    use strict;
    
    print fkt1a('bi')."\n";  # erzeugt Warnung                                                               
    print fkt2a('bi')."\n";  # erzeugt keine Warnung                                                         
    
    sub fkt1a {
       my $x = $_[0];
       sub fkt1b { return $x.'ba' }
       return fkt1b().'bo';
    }
    
    sub fkt2a {
       my $x = $_[0];
       local *t = sub { return $x.'ba' };
       return t().'bo';
    }
    
    Gruss, Xanti
     
  5. #4 angelsfall, 16.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Danke für eure Antworten.

    @hwj: Wenn ich das bei dir richtig interpretiert habe, benutzt du Verweise auf Subroutinen, aber keine Closures. Der Vorteil von Verweisen auf Subroutinen ist es, dass sie austauschbar sind wie man es ja besonders an deinem letzten Beispiel gut sieht. Closures sind von da ja gar nicht so weit entfernt. Zu einer Closures würde noch die Variable fehlen, die sich in der Subroutine befindet, die wiederum die Subroutine beinhaltet, die zurückgegeben wird, bzw der Verweis darauf. Also eine Closure ist praktisch eine Subroutine, an die Daten gebunden sind. Die Closure ist wiederum an eine andere Subroutine gebunden.

    @Xanti: Was genau macht das Sternchen vor dem Variablennamen in deinem zweiten Beispiel? Und wieso benutzt du "local" und nicht "my"? Soweit ich weiss, speichert "local" den Wert der Variable, den sie hat, temporär zwischen, um in diesem "scope" solange einen anderen Wert anzunehmen und ihn später wieder zurückzuspeichern, während "my" eine ganz neue Variable im Stack anlegt. Aber was das an dieser Stelle macht, ist mir noch nicht ganz klar ...
    Müsste man in deinem ersten Beispiel nicht einfach nur eine Referenz auf die Routine und nicht die Routine selbst übergeben, um die Warnung zu vermeiden (so wie in deinem zweiten Beispiel, wobei mir das ja noch nicht ganz klar ist ;)) bzw. einfach eine anonyme Subroutine?
     
  6. #5 Xanti, 16.12.2006
    Zuletzt bearbeitet: 16.12.2006
    Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    Mit *t wird eine Paketvariable vereinbart. Um diese auf den Bereich lokal zu beschränken, benutzt man local. Eigentlich ist das Ganze in seiner Funktion eine anonyme Subroutine. Ein bisschen verwirrt bin ich nun doch: gibts eigentlich einen Unterschied zwischen anonymen Subroutinen und Closures?

    Gut, mein Beispiel zeigt nun nicht unbedingt, wofür man closures einsetzt, eher wofür man sie "zweckentfremden" kann. Eine Bindung von Funktion und Daten existiert nicht direkt.

    Daher ein besseres Beispiel: man kann Objekte in Perl erzeugen, ohne objektorientiert programmieren zu können. Bei Bedarf liefer ich ein Beispiel.

    Gruss, Xanti
     
  7. #6 angelsfall, 16.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Es gibt definitiv einen Unterschied zwischen anonymen Subroutinen und Closures. Es geht eben um diese eine Variable, die konserviert wird. Eine Closure muss nicht zwingen durch eine anonyme Subroutine erzeugt werden. Sie kann auch einen Namen tragen, wird aber eben nur als Referenz übergeben.

    Beispiel mit Referenz auf Subroutine:
    Code:
    #!/usr/bin/perl -wl
    
    use strict;
    
    sub output {
    	my @data = @_;
    	my $string = join " " , @data;
    	return $string;
    }
    
    my $makeout = \&output;
    print $makeout->(qw/ich bin eine kleine kuh/);
    
    # Gleiches Beispiel mit Referenz auf anonyme Subroutine
    my $makeout2 = sub {
    	my @data = @_;
    	my $string = join " " , @data;
    	return $string;
    };
    
    print $makeout2->(qw/du bist ein kleiner hase/) ;
    
    Komplexeres Beispiel mit anonymen Referenzen
    (In Anlehnung an das Beispiel von R. Schwartz)
    Code:
    #!/usr/bin/perl -w
    
    use strict;
    
    sub queryData {
    	my %args = @_;
    	my $input = $args{'input'};
    	my $output = $args{'output'};
    	my $process = $args{'process'};
    	my $prompt = $args{'prompt'};
    
    	$output->($prompt);
    	while (my $cmd = $input->()) {
    		$output->($process->($cmd));
    		$output->($prompt);
    	}
    }
    
    my $makeShell = \&queryData;
    $makeShell->(
    	'input'   => sub { return <STDIN> },
    	'output'  => sub { print @_ },
    	'process' => sub {
    		my $cmd = $_[0];
    		chomp($cmd);
    		last if ($cmd eq "exit");
    		return qx/$cmd/;
    	},
    	'prompt'  => "myShell> ",
    );
    
    Beispiel mit Closures:
    Code:
    #!/usr/bin/perl -wl
    
    use strict;
    
    sub makeSetGet {
    	my $a; # Diese Variable macht die unten zurückgegebenen Subroutinen zur Closures.
    
    	return {
    		'set' => sub { $a = shift },
    		'get' => sub { $a }
    	}
    }
    
    my $a = makeSetGet();
    
    $a->{set}->("kuh");
    print $a->{'get'}->();
    
    $a->{set}->("hase");
    print $a->{'get'}->();
    
     
  8. Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    Die Variable macht also den grossen Unterschied. Wieder was gelernt. Ist wirklich eine interessante Diskussion. :)

    Theoretisch solltest Du Dir mittlerweile Deine Ausgangsfrage selber beantworten können. Mit Closures kann man Funktionen (Methoden) an Variablen binden und damit Objekte erzeugen.

    Gruss, Xanti
     
  9. #8 angelsfall, 16.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Ja. Theoretisch kann ich mir das auch alles Beantworten. Wie gesagt, mir fehlt die Praxis. Wann sind sie nützlich und gibt es Standardfälle? Weil das ist der Punkt, der mir noch zu einem glücklichen Zusammensein mit Closures fehlt ;)

    Aber vielleicht kommt das auch einfach mit der Zeit ...
     
  10. Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    Ich denke mal, ausserhalb der objektorientierten Programmierung gibt wenig Anwendung für Closures.
     
  11. #10 angelsfall, 17.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Komisch, und ich dachte immer, dass sie grade bei OOP überflüssig seien ;)
    Wenn man sich so umhört, werden Closures glaube ich eher selten benutzt, aber trotzdem sehr angepriesen. Was ich aber momentan more sexy finde, sind die Referenzen auf anonyme Subroutinen. Damit lassen sich schöne Dinge machen ;)

    (Anmerkung: Habe irgendwo gelesen, dass Closures in der Praxis meist zum Iterieren über Arrays benutzt werden und teilweise auch, um Rekursion zu vermeiden. Belegen kann ich die Aussagen jetzt allerdings nicht. Muss ma schaun, ob ich da noch was finde.)
     
  12. #11 angelsfall, 20.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Ich muss mich hier etwas korrigieren.
    Eine Closure sollte eine anonyme Subroutine sein, da das Problem mit benamten Subroutinen, die in einer Subroutine definiert sind (=nested subroutines), ist, dass diese eine Kopie dieser "konservierten" Variable, also der Umgebung der äußeren Subroutine, des ersten Aufrufs der äußeren Subroutine behalten und diese bei erneuten Aufrufen nicht mitaktualisert wird. Dieses Problem wird durch anonyme Subreferenzen behoben.

    Funktioniert nicht:
    Code:
    #!/usr/bin/perl
    
      use strict;
    
      sub print_power_of_2 {
        my $x = shift;
    
        sub power_of_2 {
          return $x ** 2; 
        }
    
        my $result = power_of_2();
        print "$x^2 = $result\n";
      }
    
      print_power_of_2(5);
      print_power_of_2(6);
    
    Output:
    Code:
      5^2 = 25
      6^2 = 25
    
    Funktioniert:
    Code:
      #!/usr/bin/perl
    
      use strict;
    
      sub print_power_of_2 {
        my $x = shift;
    
        # hier wurde die routine "anonymisiert"
        my $func_ref = sub {
          return $x ** 2;
        };
    
        my $result = &$func_ref();
        print "$x^2 = $result\n";
      }
    
      print_power_of_2(5);
      print_power_of_2(6);
    
    Output:
    Code:
      5^2 = 25
      6^2 = 36
    
    Quelle: http://www.perl.com/pub/a/2002/05/07/mod_perl.html
     
  13. DaMutz

    DaMutz Doppel-As

    Dabei seit:
    18.10.2003
    Beiträge:
    149
    Zustimmungen:
    0
    Ort:
    Giebenach / Schweiz
    Im Buch "Programmieren mit Perl" steht noch folgendes Beispiel:
    Code:
    print "Sei ", red("vorsichtig"), "mit diesem ", green("Licht"), "!!!";
    
    Soll eine HTML ausgabe sein mit verschiedenen farbigen Wörter.

    Code:
    @colors = qw(red blue green yellow orange purple violet);
    for my $name (@colors) {
         no strict 'refs';     # Symbolische Referenzen erlauben.
         *$name = *{uc $name} = sub { "<FONT COLOR='$name'>@_</FONT>" };
    }
    
    Ich kann nicht so gut Perl programmieren und habe das Buch einfach einmal gekauft, aus diesem Grund gibt es keine Erklärung...

    Aber ich denke es zeigt ein mögliches Anwendungsszenario.
     
  14. Anzeige

    Vielleicht findest du HIER Antworten.
    Registrieren bzw. einloggen, um diese und auch andere Anzeigen zu deaktivieren
  15. Xanti

    Xanti Mouse Organist

    Dabei seit:
    05.09.2004
    Beiträge:
    1.855
    Zustimmungen:
    0
    Streng genommen handelt es sich dabei aber um anonyme Subroutinen, nicht um Closures (s.o.). :)
     
  16. #14 angelsfall, 31.12.2006
    angelsfall

    angelsfall Routinier

    Dabei seit:
    09.05.2005
    Beiträge:
    315
    Zustimmungen:
    0
    Ort:
    Berlin
    Ja, richtig. Wobei ich sehr oft lese, dass anonyme Subroutinen als Closures bezeichnet werden. Aber der Name würde da auch keinen Sinn machen (closure - das Verschließen), eine Variable wird eben eingeschloßen (und somit konserviert und am Leben erhalten). Trotzdem ein schönes Beispiel für anonyme Subroutinen ;)
     
Thema:

Closures in Perl

Die Seite wird geladen...

Closures in Perl - Ähnliche Themen

  1. Linux Foundation: Hyperledger-Projekt startet mit 30 Mitgliedern

    Linux Foundation: Hyperledger-Projekt startet mit 30 Mitgliedern: Das Hyperledger-Projekt der Linux Foundation will eine neue Form der dezentralisierten Kontoführung nach dem Prinzip der »distributed ledger« bei...
  2. Perl 6 offiziell vorgestellt

    Perl 6 offiziell vorgestellt: Wie erwartet, ist die Version C(hristmas) von Perl 6 veröffentlicht worden. Perl 6 stellt nicht, wie der Name suggeriert, einen Nachfolger von...
  3. Perl: 20 Jahre CPAN

    Perl: 20 Jahre CPAN: Vor 20 Jahren wurde das erste Modul in das Comprehensive Perl Archive Network (CPAN) hochgeladen, woran Neil Bowers mit einem Abriss der...
  4. Perl 5.22.0 freigegeben

    Perl 5.22.0 freigegeben: Die neue Version 5.22 von Perl bringt den Anwendern mehr Sicherheit bei Eingabedateien, Unicode 7.0 und zahlreiche weitere Verbesserungen....
  5. [Perl] Perl OO Methodenaufruf in anderem Objekt

    [Perl] Perl OO Methodenaufruf in anderem Objekt: Hallo, Ich bin dabei in Perl ein Pokerspiel zu programmieren, hänge aber momentan an einem Problem, wo ich nicht weiterkomme. Ich habe die...