2007/10/19

Currying und partielle Funktionsapplikation Part 2

Letztes Mal habe ich Currying und partielle Funktionsapplikation in C#, Scheme und Ruby verglichen. Da ich aber funktionale Programmierung hauptsächlich in meiner Freizeit studiere und meine Brötchen immer noch vorwiegend mit .NET verdiene, ist es für mich - eine zugegebenermassen höchst angenehme - Pflicht, das ganze noch kurz in F# anzuschauen.

Deshalb hier also nur ganz kurz als Ergänzung zum letzten Post das Beispiel in F#:


#light
let add a b = a + b
printf "result %i" ((add 2) 3)

let inc = add 1
let result = inc 3
printf "\nresult %i" result

Huh!? Currying wird in F# (wie in Haskell auch) schon von der Sprache selbst unterstützt und es ist hier möglich, eine beliebige Funktion ohne Umweg partiell zu applizieren.

Nice.

2007/10/17

Currying und partielle Funktionsapplikation

Vor einiger Zeit habe ich mich (hier) mit Currying und partieller Funktionsapplikation in C# 3.0 beschäftigt. Ich will in diesem Eintrag die Implementation von Wes aufgreifen und anschauen wie eine solche in Scheme und Ruby aussehen könnte.

Grundlage ist die simple Addition:


Func<int,int,int> add = (x,y) => x + y;

Die Funktion Curry für eine generische Funktion mit zwei Argumenten kann in C# als Extension Method implementiert werden und sieht in der Implementation von Wes Dyer folgendermassen aus:

public static Func<A, Func<B, R>> Curry<A, B, R>(
this Func<A, B, R> f)
{
return a => b => f(a, b);
}

Mit dieser Funktion ist es also möglich, die Argumente schrittweise zu binden wie wir in der Anwendung klar erkennen können:

Func<int,Func<int,int>> curriedAdd = add.Curry();
Console.WriteLine(curriedAdd(3)(5)); //8

Wie Wes weiter erklärt, kann dieses Konzept weiter generalisiert werden in ein Konzept mit dem Namen 'partielle Funktionsapplikation'. Mit diesem Konzept ist es möglich aus einer Funktion eine ganze Familie von Funktionen zu erzeugen. In unserem Beispiel wollen wir bei der Funktion add das erste Argument mit 1 binden und so eine triviale Inkrementierungs-Funktion erhalten.

Func<int, int> inc = add.Partial(1);

Die Funktion Partial zitiere ich auch wieder direkt von Wes. Sie sieht folgendermassen aus:

public static Func<B, R> Partial<A, B, R>(
this Func<A, B, R> f, A a)
{
return b => f(a, b);
}

Thanks again, Wes!

Wenn ich mir das so anschaue, erinnert es mich ein klein wenig an das Überladen von Methoden in der Objektorientierung. Mit beiden Konzepten ist es möglich, den Aufruf einer Funktion/Methode zu vereinfachen indem bestimmte alternative Signaturen angeboten werden. (Die Puristen unter euch mögen mir diesen profanen Vergleich verzeihen!)

Als relativer Anfänger im Umgang mit Scheme habe ich mir angeschaut wie eine solche Implementation in diesem LISP-Dialekt aussehen könnte. Für die Curry-Funktion bin ich auf folgende Implementation gekommen.

(define add
(lambda (a b)
(+ a b)))

(define curry
(lambda (f)
(lambda (a)
(lambda (b)
(f a b)))))

(define curried-add (curry add))
((curried-add 3) 5) ;; => 8

Auffallend ist hier, dass ich kein funktionales Äquivalent für 'Extension Methods' gefunden habe. Erfahrenere Scheme Benutzer könnten hier vermutlich mit einer prägnanteren Implementation aufwarten.

Trotzdem hier auch noch die Implementation von Partial:

(define partial
(lambda (f a)
(lambda (b)
(f a b))))

(define inc (partial add 1))
(inc 3) ;; => 4

Jetzt wollen wir aber auch noch sehen wie das ganze in Ruby aussehen könnte. Zuerst die Funktion Curry:

add = lambda{|a,b| a + b}
class << add
def curry
lambda{|a| lambda{|b| self.call(a,b)}}
end
end

curried_add = add.curry
curried_add.call(3).call(6) # => 9

Hier habe ich es vorgezogen, Curry auf dem Objekt add zu implementieren da mir die Anwendung so einfacher schien. Und schliesslich auch eine Ruby-Version von Partial:


class << add
def partial val
lambda{|a| self.call(a,val)}
end
end

inc = add.partial 1
inc 4 # => 5

Wenn ich die verschiedenen Implementation miteinander vergleiche, fällt mir persönlich zuerst einmal der etwas grössere Programmieraufwand für C# auf. Es wird wieder einmal die Tatsache deutlich, dass es sich um eine statisch typisierte Sprache handelt und wir zugunsten einer Typenprüfung beim Kompilieren etwas mehr schreiben müssen. Bei der Ruby-Version fällt vor allem der explizite Aufruf von Proc#call auf.

Als nächstes gäbe es dann wohl den Y-Combinator in der verschiedenen Sprachen zu vergleichen.

2007/10/14

Mixins und Klassenmethoden

Als ich zum ersten Mal dem Prinzip der Objektorientierung begegnete welches besagt 'Bevorzuge Komposition der Vererbung' fand ich dieses auf Anhieb einleuchtend. Obwohl Polymorphismus im Fall von einer 'is a'-Beziehung und einer noch nicht zu tiefen Klassenhierarchie sicher nahe liegend ist und eine perfekte Lösung darstellt, gibt es trotzdem viele Fälle wo eine solche Kopplung zu weit geht. (Und wir womöglich sogar das LSP verletzen würden!)
Module in Ruby sind für solche Situationen natürlich geradezu prädestiniert da sie uns erlauben, solche Beziehungen mit Mixins abzubilden. Mit Modulen kann in Ruby zudem auch das Konzept der Mehrfachvererbung implementiert werden.

Nun hatte ich aber diese Woche die Anforderung, Klassen über Module mit Methoden zu erweitern und nicht Instanzen. Aufgrund der Art wie Ruby das Schlüsselwortes 'self' handhabt, lassen sich Klassenmethoden nicht ganz so einfach wie Instanzmethoden 'hineinmixen'.

Aber wie immer mit Ruby war Hilfe nicht weit und die Dokumentation führte zu der Methode 'included(othermod)'. Mit diesem Callback können nun auch Klassen mit Methoden erweitert werden ohne dass die Syntax vom Client her angepasst werden müsste:


module Mixin
def self.included other_module
other_module.extend ClassMethods
end

module ClassMethods
def bar?
true
end
end
end

class Foo
include Mixin
end

puts Foo.bar? #=> true