Die Grundregel lautet, dass in der FP-Programmierung die gleichen Funktionen ausgeführt werden wie in der OO-Programmierung die Objekte. Sie können ihre Methoden aufrufen (naja, die "call" -Methode) und sie reagieren gemäß einigen gekapselten internen Regeln. Insbesondere können Sie in jeder anständigen FP-Sprache "Instanzvariablen" in Ihrer Funktion mit Closures / lexikalischem Scoping verwenden.
var make_OO_style_counter = function(){
return {
counter: 0
increment: function(){
this.counter += 1
return this.counter;
}
}
};
var make_FP_style_counter = function(){
var counter = 0;
return fucntion(){
counter += 1
return counter;
}
};
Die nächste Frage ist nun, was Sie unter einer Schnittstelle verstehen. Ein Ansatz ist die Verwendung von nominalen Schnittstellen (entspricht der Schnittstelle, wenn dies angegeben ist). Diese hängt normalerweise stark von der von Ihnen verwendeten Sprache ab. Lassen Sie sie daher für letztere. Die andere Art, eine Schnittstelle zu definieren, ist die strukturelle Art, zu sehen, welche Parameter empfangen und zurückgegeben werden. Dies ist die Art von Schnittstelle, die Sie normalerweise in dynamischen Sprachen sehen, die vom Typ Ente stammen, und sie passt sehr gut zu allen FP: Eine Schnittstelle besteht nur aus den Typen der Eingabeparameter für unsere Funktionen und den Typen, die sie zurückgeben, sodass alle Funktionen mit den übereinstimmen richtige Typen passen zur Schnittstelle!
Daher besteht die einfachste Möglichkeit, ein Objekt darzustellen, das mit einer Schnittstelle übereinstimmt, darin, einfach eine Gruppe von Funktionen zu haben. Normalerweise umgehen Sie die Hässlichkeit, wenn Sie die Funktionen einzeln übergeben, indem Sie sie in eine Art Protokoll packen:
var my_blarfable = {
get_name: function(){ ... },
set_name: function(){ ... },
get_id: function(){ ... }
}
do_something(my_blarfable)
Mit nackten Funktionen oder Aufzeichnungen von Funktionen können Sie die meisten Ihrer häufigsten Probleme auf "fettfreie" Weise lösen, ohne jede Menge Boilerplate. Wenn Sie etwas Fortgeschritteneres benötigen, bieten Ihnen manchmal Sprachen zusätzliche Funktionen. Ein Beispiel, das erwähnt wird, sind Haskell-Typklassen. Typklassen ordnen einen Typ im Wesentlichen einem dieser Funktionsdatensätze zu und ermöglichen das Schreiben von Dingen, sodass die Wörterbücher implizit sind und bei Bedarf automatisch an innere Funktionen übergeben werden.
-- Explicit dictionary version
-- no setters because haskell doesn't like mutable state.
data BlargDict = BlargDict {
blarg_name :: String,
blarg_id :: Integer
}
do_something :: BlargDict -> IO()
do_something blarg_dict = do
print (blarg_name blarg_dict)
print (blarg_id blarg_dict)
-- Typeclass version
class Blargable a where
blag_name :: a -> String
blag_id :: a -> String
do_something :: Blargable a => a -> IO
do_something blarg = do
print (blarg_name blarg)
print (blarg_id blarg)
Eine wichtige Anmerkung zu Typklassen ist jedoch, dass die Wörterbücher den Typen und nicht den Werten zugeordnet sind (wie dies in den Wörterbuch- und OO-Versionen der Fall ist). Dies bedeutet, dass Sie im Typensystem keine "Typen" mischen können [1]. Wenn Sie eine Liste von "Blargables" oder eine Binärfunktion für Blargables benötigen, werden bei Typeclasses alle Werte auf den gleichen Typ beschränkt, während Sie bei der Dictionary-Methode Blargables mit unterschiedlichen Ursprüngen erhalten (welche Version besser ist, hängt stark davon ab, was Sie sind) tun)
[1] Es gibt fortgeschrittene Möglichkeiten, "existenzielle Typen" zu erstellen, aber normalerweise ist es die Mühe nicht wert.