In reine Funktionen umgestalten (LINQ to XML)
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 Artikel wird erläutert, was eine reine Funktion ist und was nicht. Im Tutorial: Bearbeiten von Inhalten in einem WordprocessingML-Dokument wird gezeigt, wie Sie ein WordprocessingML-Dokument bearbeiten können. Außerdem enthält dieses Tutorial zwei Beispiele für das Umgestalten mithilfe einer reinen Funktion.
In den folgenden Beispielen werden zwei nicht reine Funktionen einer reinen Funktion gegenübergestellt.
Beispiel: Implementieren einer nicht reinen Funktion, die einen statischen Klassenmember ändert
Im folgenden Code ist die HyphenatedConcat
-Funktion keine reine Funktion, da sie den statischen aMember
-Klassenmember ändert:
public class Program
{
private static string aMember = "StringOne";
public static void HyphenatedConcat(string appendStr)
{
aMember += '-' + appendStr;
}
public static void Main()
{
HyphenatedConcat("StringTwo");
Console.WriteLine(aMember);
}
}
Module Module1
Dim aMember As String = "StringOne"
Public Sub HyphenatedConcat(ByVal appendStr As String)
aMember = aMember & "-" & appendStr
End Sub
Sub Main()
HyphenatedConcat("StringTwo")
Console.WriteLine(aMember)
End Sub
End Module
Dieses Beispiel erzeugt die folgende Ausgabe:
StringOne-StringTwo
Beachten Sie, dass es keine Rolle spielt, ob die zu ändernden Daten public
-Zugriff oder private
-Zugriff besitzen oder ein static
-Member, ein shared
-Member oder ein Instanzmember sind. Reine Funktionen führen zu keinerlei Änderungen an Daten außerhalb der Funktion.
Beispiel: Implementieren einer nicht reinen Funktion, die einen Parameter ändert
Außerdem ist die folgende Version derselben Funktion keine reine Funktion, weil sie den Inhalt ihres Parameters ändert, sb
.
public class Program
{
public static void HyphenatedConcat(StringBuilder sb, String appendStr)
{
sb.Append('-' + appendStr);
}
public static void Main()
{
StringBuilder sb1 = new StringBuilder("StringOne");
HyphenatedConcat(sb1, "StringTwo");
Console.WriteLine(sb1);
}
}
Module Module1
Public Sub HyphenatedConcat(ByVal sb As StringBuilder, ByVal appendStr As String)
sb.Append("-" & appendStr)
End Sub
Sub Main()
Dim sb1 As StringBuilder = New StringBuilder("StringOne")
HyphenatedConcat(sb1, "StringTwo")
Console.WriteLine(sb1)
End Sub
End Module
Diese Version des Programms produziert dieselbe Ausgabe wie die erste Version, weil die HyphenatedConcat
-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 HyphenatedConcat
mit Wertparameterübergabe arbeitet.
Wichtig
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 eine Funktion ist die Referenzparameterübergabe nicht unbedingt erforderlich.
Beispiel: Implementieren einer reinen Funktion
Die nächste Version des Programms zeigt, wie die HyphenatedConcat
-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
. Beachten Sie, dass der verkettete Wert in der Zwischenvariable s2
gespeichert wird, um ihn beizubehalten.
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 finden Sie unter Übersicht über Standardabfrageoperatoren (C#) und Übersicht über Standardabfrageoperatoren (Visual Basic).