Wenn ich in einem "funktionalen" Stil programmieren möchte, durch was würde ich eine Schnittstelle ersetzen?
interface IFace
{
string Name { get; set; }
int Id { get; }
}
class Foo : IFace { ... }
Vielleicht ein Tuple<>
?
Tuple<Func<string> /*get_Name*/, Action<String> /*set_Name*/, Func<int> /*get_Id*/> Foo;
Der einzige Grund, warum ich überhaupt eine Schnittstelle benutze, ist, dass ich immer bestimmte Eigenschaften / Methoden zur Verfügung haben möchte.
Bearbeiten: Einige Details darüber, was ich denke / versuche.
Angenommen, ich habe eine Methode, die drei Funktionen übernimmt:
static class Blarf
{
public static void DoSomething(Func<string> getName, Action<string> setName, Func<int> getId);
}
Mit einer Instanz von Bar
kann ich diese Methode verwenden:
class Bar
{
public string GetName();
public void SetName(string value);
public int GetId();
}
...
var bar = new Bar();
Blarf.DoSomething(bar.GetName, bar.SetName, bar.GetId);
Aber das ist ein bisschen schmerzhaft, wie ich bar
dreimal in einem einzigen Anruf erwähnen muss . Außerdem habe ich nicht wirklich vor, dass Anrufer Funktionen aus verschiedenen Instanzen bereitstellen
Blarf.DoSomething(bar1.GetName, bar2.SetName, bar3.GetId); // NO!
In C # gibt interface
es eine Möglichkeit, damit umzugehen. aber das scheint ein sehr objektorientierter Ansatz zu sein. Ich frage mich, ob es eine funktionalere Lösung gibt: 1) Übergeben Sie die Funktionsgruppe zusammen, und 2) stellen Sie sicher, dass die Funktionen richtig zueinander in Beziehung stehen.
Antworten:
Behandeln Sie funktionale Programmierung nicht als dünne Schicht gegenüber imperativer Programmierung. Es gibt viel mehr als nur einen syntaktischen Unterschied.
In diesem Fall haben Sie eine
GetID
Methode, die die Eindeutigkeit von Objekten impliziert. Dies ist kein guter Ansatz zum Schreiben von Funktionsprogrammen. Vielleicht können Sie uns das Problem mitteilen, das Sie lösen möchten, und wir können Ihnen aussagekräftigere Ratschläge geben.quelle
Haskell und seine Derivate haben Typklassen, die Schnittstellen ähneln. Es hört sich so an, als würden Sie sich fragen, wie die Verkapselung erfolgen soll. Dies ist eine Frage, die sich auf Typsysteme bezieht. Das hindley Milner-Typensystem ist in funktionalen Sprachen üblich, und es verfügt über Datentypen, die dies in verschiedenen Sprachen auf unterschiedliche Weise für Sie tun.
quelle
Es gibt verschiedene Möglichkeiten, einer Funktion den Umgang mit mehreren Eingaben zu ermöglichen.
Erste und häufigste: Parametrischer Polymorphismus.
Dadurch kann eine Funktion auf beliebige Typen einwirken:
Was nett ist, aber nicht den dynamischen Versand bietet, den OO-Schnittstellen haben. Dafür hat Haskell Typenklassen, Scala Implikationen usw
Zwischen diesen beiden Mechanismen können Sie alle möglichen komplexen und interessanten Verhaltensweisen Ihrer Typen ausdrücken.
quelle
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.
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:
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.
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.
quelle
Ich denke, es wird sprachspezifisch sein. Ich komme aus einem lispy Hintergrund. In vielen Fällen brechen Schnittstellen mit dem Zustand das Funktionsmodell bis zu einem gewissen Grad. So ist beispielsweise in CLOS LISP weniger funktional und einer imperativen Sprache näher. Im Allgemeinen sind erforderliche Funktionsparameter in Kombination mit Methoden höherer Ebenen wahrscheinlich das, wonach Sie suchen.
quelle