Dynamic Closures
 
StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern

In SpracheSmalltalk heißen die Blöcke, SpracheRuby kennt Procs und der Autor von SpracheD spricht von DynamicClosures. Weitere Bezeichnungen könnten sein: AnonymeFunktionen? (Java?) oder Continuations (das ist schon wieder mehr als eine DynamicClosure?, vielleicht findet sich ja jemand für eine Erläuterung).

Im Grunde geht es darum, eine Funktion lokal und mit Zugriff auf den lokalen Kontext definieren zu können und diese dann dort oder sogar außerhalb des eigentlichen Kontextes verwenden zu können. Manche Sprachen erwarten für lokale Funktionen einen Namen, andere erlauben namenlose (anonyme) Funktionen.

Mit Closures lassen sich sehr elegant interne Iteratoren definieren, siehe WardsWiki:InternalIterator. In Sprachen, denen Closures fehlen, werden deshalb häufiger externe Iteratoren ( WardsWiki:ExternalIterator) verwendet. Diese Spracheigenschaft hat daher Einfluß auf das Schnittstellen-Design von Container-Bibliotheken.

Siehe auch Wikipedia deutsch, Wikipedia englisch und FolDoc, WardsWiki:BlocksInManyLanguages

SpracheD
Siehe http://www.digitalmars.com/d/function.html

SpracheHaskell

In der SpracheHaskell benutzt man das ständig, entweder ausdrücklich mit der Lambda-Notation

map (\x -> x+1) list

oder mit teilweiser Funktionsauswertung

map (1+) list
.

Übrigens kann man in Sprachen, die Closures unterstützen, auch Modaden ausdrücken: http://moonbase.rydia.net/mental/writings/programming/monads-in-ruby/00introduction.html

SpracheJava

In der SpracheJava kann man AnonymeInnereKlassen? benutzen. Ist zwar ein wenig umständlich, funktioniert aber.

        public void printAll(Collection myCollection, final PrintStream out) {
          CollectionUtils.forEach(myCollection, new IBlock() {
            public void perform(Object each) {
              out.println(each);
            }
          }); 
        }

Nicht jeder ist davon angetan:

A good case in point is what happened when ex-Smalltalkers started in Java. Initially many people, including me, experimented with using anonymous inner classes to do many of things that we'd done with blocks in smalltalk. But the resulting code was just too messy and ugly so we gave up.
Martin Fowler in http://martinfowler.com/bliki/Closures.html

http://c2.com/ppr/wiki/JavaIdioms/BlocksInJava.html

Mittlerweile tut sich was:

SpracheModula3

In der SpracheModula3 sind Unterprogramme in Unterprogrammen erlaubt, sie müssen aber immer einen Namen tragen.

PROCEDURE InverseXPlusLogX (y : LONGREAL; ): LONGREAL =

    PROCEDURE F (x: LONGREAL; ): LONGREAL =
      BEGIN
        RETURN x + Math.log(x) - y;
      END F;

    PROCEDURE DF (x: LONGREAL; ): LONGREAL =
      BEGIN
        RETURN 1.0D0 + 1.0D0 / x;
      END DF;

  CONST
    tol = 1.0D-13;
    maxIter = 20;

  BEGIN
    RETURN Newton(F, DF, 1.0D0, tol, maxIter);
  END InverseXPlusLogX;

SprachePerl

           my $secret_version = '1.001-beta';
           my $secret_sub = sub { print $secret_version };
           &$secret_sub();

Von perlsub(1).

Inplace sortieren:
           @array = sort { lc($a) cmp lc($b) } @array;

Elemente einer Liste bearbeiten:
           @array = map { "$_"x5 } @array;

Liste filtern:
           @array = grep { $_ > 5 } @array;

SprachePython

Inplace sortieren einer Liste (als Parameter wird eine Funktion erwartet, die -1, 0, oder 1 zurückgibt:
list.sort(lambda a, b: a < b and -1 or a > b and 1 or 0)
(wenn man normal aufsteigen sortieren will, reicht list.sort())

Gegen eine lokale Variable vergleichen:
    
grenzwert = 100;
filter( lambda x: x > grenzwert, collection)

Den Block durchreichen, obwohl dieser eine lokale Variable referenziert. (Dank GarbageCollector ist das auch für fette Objekte möglich!)
grenzwert = 100;
block = lambda x: x > grenzwert
block(99)          

alternativ (für komplexere Abläufe)
grenzwert = 100;
def block(x):
   return x > grenzwert

block(99)

Erzeugen einer parametrisierten Funktion
def createOffBy(offset):
  return lambda x: x + offset

# jetzt kann man f = createOffBy(10) aufrufen. f(1) gibt dann 11 zurück.

In Python kann man nur LambdaExpressions? unbenannt definieren. Ein komplexer Ablauf muss benannt werden und als Funktion definiert werden. Man kann also in Python keine echten Kontrollstrukturen definieren wie in Smalltalk oder Ruby. Man kann aber eine Funktion einer anderen als Parameter übergeben. Hier ein Beispiel für eine Funktion, die eine andere x-mal aufzurufen versucht. Die Parameter der wiederholten Funktion werden erst beim Aufruf übergeben:

# *args wird beliebige unbenannte Paramater enthalten 
# **kwargs beliebige benannte Parameter
def retry(count, f, *args, **kwargs):
   while count > 0:
      count -= 1
      try:
         return f(*args, **kwargs)
      except:
         pass
   return f(*args, **kwargs) #hier wird Exception weitergereicht

#Aufruf 
def myfun(resource, user, password):
  # tue was kompliziertes 

#Versuche es 5x 
retry(4, f, "db", "myusername", password="mypassword")

Ein Generator, der mehrere Werte zurückgibt:
def address(name, street, city):
   yield name
   yield street
   yield city

# Aufruf:

for line in address("Santa Claus", "Rudolfstraße 1", "Nordpol"):
  print line

Ein, recht dumm programmierter Generator, der alle Teiler einer Zahl zurükgibt:
def teiler(n):
  for t in range(1, n // 2):
    if n % t == 0:
      yield t

#Aufruf:
for t in teiler(60): 
  print t, 

#Drückt 1 2 3 4 5 6 10 12 15 20 aus.

SpracheRuby

SpracheSmalltalk

Ein Standard-Beispiel in Smalltalk wäre ein Sortblock:
    aCollection sortBlock: [ :x :y | x > y ]

Gegen eine lokale Variable vergleichen:
    | grenzwert |
    grenzwert = 100;
    aCollection select: [ :x | x > grenzwert ]

Den Block durchreichen, obwohl dieser eine lokale Variable referenziert. (Dank GarbageCollection ist das auch für fette Objekte möglich!)
    getBlock
        | grenzwert |
        grenzwert = 100;
        ^[ :x | x > grenzwert ]

    useBlock
        ^getBlock value: 99

Blöcke spielen in Smalltalk ein überaus zentrale Rolle, weil Kontrollstrukturen nicht in die Sprache eingebaut sind, sondern über Blöcke realisiert wurden:
   true
      ifTrue: [ Transcript show: "Ich bin wahr." ]
      ifFalse: [ self error ] 

Hier ist true eine globale Instanz von True und True eine Smalltalk-Klasse, die Methode ifTrue:ifFalse: mit Ausführung des ersten Blockes implementiert.

Überflüssig zu sagen, dass man Blöcke schachteln kann:
   (1 to: 200) reject: [ :x | self getBlock value: x ]

Sehr platzsparend sind Iterator-Methoden mit mehreren Blöcken:

    #('Hans' 'Klaus' 'Marion')
        do: [ :name | Transcript show: name ]
        separatedBy: [ Transcript nextPutAll: ', ' ]

SpracheCsharp

Lt. http://gnuvince.net/?p=55 wird es in C# 3.0 soetwas wie Lambda-Ausdrücke geben. Mehr dazu auch unter http://joe.truemesh.com/blog//000390.html.

SpracheGroovy

http://groovy.codehaus.org/Closures


StartSeite | Neues | TestSeite | ForumSeite | Teilnehmer | Kategorien | Index | Hilfe | Einstellungen | Ändern
Text dieser Seite ändern (zuletzt geändert: 26. August 2009 17:50 (diff))
Suchbegriff: gesucht wird
im Titel
im Text