Closures in Aktion


Bei der Diskussion um Closures in Java werden immer wieder Stimmen laut, die behaupten, Java brauche solche „Spielereien“ nicht. Deshalb hier eine kleine Spielerei:

def fix[A](start: A, f: A => A) = {
 def loop(a: A): A = {
    val fa = f(a)
    if(a == fa) a else loop(fa)
 }
 loop(start)
}

Dieser Code berechnet den Fixpunkt einer Funktion zu einem gegebenen Startwert. Oder einfacher ausgedrückt: Man ruft eine Funktion solange „auf sich selbst“ auf, bis sich nichts mehr ändert.

Ein offensichtlicher Anwendungsfall sind Iterationsverfahren wie das Newton-Verfahren. Man kann etwa die Wurzel aus 2 wie folgt berechnen:

fix[Double](1, x => (2/x+x)/2)
//-->res0: Double = 1.414213562373095

Oder eine allgemeine Wurzelfunktion schreiben:

def root(n:Double) = fix[Double](1, x => (n/x+x)/2)

root(65536)
//--> res1: Double = 256.0

Oder eine Funktion, die die einstellige Quersumme berechnet:

def digSum(n: Int) = fix[Int](n, x => x/10 + x%10)

digSum(12345)
//-->res2: Int = 6

Wie man sieht, ist unsere fix-Funktion eine nützliche und vielseitige Sache, eine Abstraktion, die uns – einmal entdeckt und implementiert – das Leben leichter macht. Aber wenn man nun die Funktion f in eine Klasse verpacken müsste, die wiederum ein gegebenes Interface implementiert, wäre die ganze Übersichtlichkeit und Eleganz dahin. Es wäre dann einfacher, das gemeinsame Muster zu ignorieren und wieder jeden Fall für sich allein zu implementieren. Und genau das passiert in Java jeden Tag. Ich denke der Codename „Mustang“ für Java 1.6 ist absolut zutreffend: Wer könnte ein besseres Wappentier für diesen Code-Stil sein als ein Wiederkäuer?

Da wir schon beim Herumspielen sind: Mit roher Gewalt kann man fix natürlich auch für ziemlich unpassende Berechnungen wie die der Fakultät verwenden, aber das heißt wahrlich mit Kanonen auf Spatzen schießen:

def fak(n: Int) = fix[(Int,Int)]((n,1),  t => if (t._1==0) t else (t._1-1, t._1*t._2))._2

fak(5)
//--> res3: Int = 120

Damit habe ich wieder einmal ein Beispiel geliefert, dass man jede gute Sache auch pervertieren kann. Oder habe ich nur eine bessere Lösung übersehen?

Advertisements

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s