Umgestalten in reine Funktionen
Aktualisiert: November 2007
Ein wichtiger Aspekt bei dem Studium reiner funktionaler Transformationen besteht darin zu lernen, wie Code mit reinen Funktionen umgestaltet werden kann.
Hinweis: |
---|
Nach der allgemeinen Nomenklatur bei der funktionalen Programmierung werden Programme mit reinen Funktionen umgestaltet. In Visual Basic und C++ geht dies mit der Verwendung von Funktionen in den jeweiligen Sprachen einher. In C# werden Funktionen aber als Methoden bezeichnet. Im Rahmen dieser Erläuterung ist die reine Funktion als C#-Methode implementiert. |
Wie bereits weiter oben erwähnt, besitzt eine reine Funktion zwei nützliche Eigenschaften:
Sie hat keine Nebenwirkungen. Die Funktion ändert keine Variablen oder Daten irgendeines Typs außerhalb der Funktion.
Sie ist konsistent. Bei identischen Eingabedaten gibt die Funktion immer denselben Ausgabewert zurück.
Eine Möglichkeit des Umstiegs auf die funktionale Programmierung besteht darin, vorhandenen Code umzugestalten und so unnötige Nebenwirkungen und externe Abhängigkeiten abzuschaffen. Auf diese Weise können Sie Versionen von reinen Funktionen von vorhandenem Code erstellen.
In diesem Thema wird erläutert, was eine reine Funktion ist und was nicht. Im Lernprogramm Bearbeiten des Inhalts eines WordprocessingML-Dokuments wird gezeigt, wie Sie ein WordprocessingML-Dokument bearbeiten können. Außerdem enthält dieses Lernprogramm zwei Beispiele für das Umgestalten mithilfe einer reinen Funktion.
Beseitigen von Nebenwirkungen und externen Abhängigkeiten
In den folgenden Beispielen werden zwei nicht reine Funktionen einer reinen Funktion gegenübergestellt.
Nicht reine Funktion, die einen Klassenmember ändert
Im folgenden Code ist die HypenatedConcat-Funktion keine reine Funktion, da sie den aMember-Datenmember in der Klasse ändert:
public class Program
{
private static string aMember = "StringOne";
public static void HypenatedConcat(string appendStr)
{
aMember += '-' + appendStr;
}
public static void Main()
{
HypenatedConcat("StringTwo");
Console.WriteLine(aMember);
}
}
Module Module1
Dim aMember As String = "StringOne"
Public Sub HypenatedConcat(ByVal appendStr As String)
aMember = aMember & "-" & appendStr
End Sub
Sub Main()
HypenatedConcat("StringTwo")
Console.WriteLine(aMember)
End Sub
End Module
Dieser Code erzeugt die folgende Ausgabe:
StringOne-StringTwo
Ob die zu ändernden Daten public-Zugriff oder private-Zugriff besitzen oder ein static-(shared-)Member bzw. ein Instanzmember sind, spielt keine Rolle. Reine Funktionen führen zu keinerlei Änderungen an Daten außerhalb der Funktion.
Nicht reine Funktion, die ein Argument ändert
Außerdem ist die folgende Version derselben Funktion keine reine Funktion, weil sie den Inhalt ihres Parameters, sb, ändert.
public class Program
{
public static void HypenatedConcat(StringBuilder sb, String appendStr)
{
sb.Append('-' + appendStr);
}
public static void Main()
{
StringBuilder sb1 = new StringBuilder("StringOne");
HypenatedConcat(sb1, "StringTwo");
Console.WriteLine(sb1);
}
}
Module Module1
Public Sub HypenatedConcat(ByVal sb As StringBuilder, ByVal appendStr As String)
sb.Append("-" & appendStr)
End Sub
Sub Main()
Dim sb1 As StringBuilder = New StringBuilder("StringOne")
HypenatedConcat(sb1, "StringTwo")
Console.WriteLine(sb1)
End Sub
End Module
Diese Version des Programms produziert dieselbe Ausgabe wie die erste Version, weil die HypenatedConcat-Funktion durch Aufrufen der Append-Memberfunktion den Wert (Status) ihres ersten Parameters geändert hat. Beachten Sie, dass diese Änderung trotz der Tatsache auftritt, dass HypenatedConcat mit Wertparameterübergabe arbeitet.
Wichtiger Hinweis: |
---|
Wenn Sie bei Verweistypen einen Parameter nach Wert übergeben, führt dies zu einer Kopie des Verweises auf ein zu übergebendes Objekt. Diese Kopie ist weiterhin mit denselben Instanzdaten wie der ursprüngliche Verweis verknüpft (so lange, bis die Verweisvariable einem neuen Objekt zugewiesen wird). Für das Ändern eines Parameters durch einen Parameter ist die Referenzparameterübergabe nicht unbedingt erforderlich. |
Reine Funktion
Die nächste Version des Programms zeigt, wie die HypenatedConcat-Funktion als reine Funktion implementiert werden kann.
class Program
{
public static string HyphenatedConcat(string s, string appendStr)
{
return (s + '-' + appendStr);
}
public static void Main(string[] args)
{
string s1 = "StringOne";
string s2 = HyphenatedConcat(s1, "StringTwo");
Console.WriteLine(s2);
}
}
Module Module1
Public Function HyphenatedConcat(ByVal s As String, ByVal appendStr As String) As String
Return (s & "-" & appendStr)
End Function
Sub Main()
Dim s1 As String = "StringOne"
Dim s2 As String = HyphenatedConcat(s1, "StringTwo")
Console.WriteLine(s2)
End Sub
End Module
Auch diese Version erzeugt dieselbe Zeile in der Ausgabe: StringOne-StringTwo. Um den verketteten Wert beizubehalten, wird er in der Zwischenvariable s2 gespeichert.
Ein Ansatz, der sich als sehr hilfreich erweisen kann, besteht darin, Funktionen zu schreiben, die zwar lokal unrein (also lokale Variablen deklarieren und ändern), global aber rein sind. Solche Funktionen besitzen viele der wünschenswerten Zusammensetzbarkeitseigenschaften, vermeiden dabei aber einige der komplizierteren Idiome der funktionalen Programmierung, z. B. die Notwendigkeit der Verwendung der Rekursion, wenn eine einfache Schleife dasselbe Ziel erreichen würde.
Standardabfrageoperatoren
Ein wichtiges Merkmal der Standardabfrageoperatoren besteht darin, dass sie als reine Funktionen implementiert sind.
Weitere Informationen dazu finden Sie unter Übersicht über Standardabfrageoperatoren.
Siehe auch
Konzepte
Einführung in funktionale Transformationen mit reinen Funktionen