Omstrukturera till rena funktioner (LINQ till XML)
En viktig aspekt av rena funktionella transformeringar är att lära sig att omstrukturera kod med hjälp av rena funktioner.
Kommentar
Den gemensamma nomenklaturen i funktionell programmering är att du omstrukturerar program med hjälp av rena funktioner. I Visual Basic och C++, överensstämmer detta med användningen av funktioner på respektive språk. I C#kallas dock funktioner för metoder. I den här diskussionen implementeras en ren funktion som en metod i C#.
Som tidigare nämnts i det här avsnittet har en ren funktion två användbara egenskaper:
- Det har inga biverkningar. Funktionen ändrar inga variabler eller data av någon typ utanför funktionen.
- Det är konsekvent. Med samma uppsättning indata returnerar den alltid samma utdatavärde.
Ett sätt att övergå till funktionell programmering är att omstrukturera befintlig kod för att eliminera onödiga biverkningar och externa beroenden. På så sätt kan du skapa rena funktionsversioner av befintlig kod.
I den här artikeln beskrivs vad en ren funktion är och vad den inte är. Självstudiekursen : Manipulera innehåll i ett WordprocessingML-dokument visar hur du manipulerar ett WordprocessingML-dokument och innehåller två exempel på hur du omstrukturerar med hjälp av en ren funktion.
I följande exempel kontrasterar två icke-rena funktioner och en ren funktion.
Exempel: Implementera en icke-ren funktion som ändrar en statisk klassmedlem
I följande kod HyphenatedConcat
är funktionen inte en ren funktion eftersom den ändrar den aMember
statiska klassmedlemmen:
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
Det här exemplet genererar följande utdata:
StringOne-StringTwo
Observera att det är irrelevant om data som ändras har eller private
har public
åtkomst eller är medlemstatic
, shared
medlem eller instansmedlem. En ren funktion ändrar inte några data utanför funktionen.
Exempel: Implementera en icke-ren funktion som ändrar en parameter
Dessutom är följande version av samma funktion inte ren eftersom den ändrar innehållet i parametern . 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
Den här versionen av programmet genererar samma utdata som den första versionen, eftersom HyphenatedConcat
funktionen har ändrat värdet (tillståndet) för den första parametern genom att Append anropa medlemsfunktionen. Observera att den här ändringen sker trots att HyphenatedConcat
parametern call-by-value används.
Viktigt!
Om du skickar en parameter efter värde för referenstyper resulterar det i en kopia av referensen till ett objekt som skickas. Den här kopian är fortfarande associerad med samma instansdata som den ursprungliga referensen (tills referensvariabeln har tilldelats till ett nytt objekt). Anrop efter referens krävs inte nödvändigtvis för att en funktion ska kunna ändra en parameter.
Exempel: Implementera en ren funktion
Nästa version av programmet visar hur du HyphenatedConcat
implementerar funktionen som en ren funktion.
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
Återigen genererar den här versionen samma utdatarad: StringOne-StringTwo
. Observera att för att behålla det sammanfogade värdet lagras det i den mellanliggande variabeln s2
.
En metod som kan vara mycket användbar är att skriva funktioner som är lokalt orena (det vill säga deklarerar och ändrar lokala variabler) men som är globalt rena. Sådana funktioner har många av de önskvärda sammansättningsegenskaperna, men undvik några av de mer invecklade funktionella programmerings-idiomerna, till exempel att behöva använda rekursion när en enkel loop skulle åstadkomma samma sak.
Vanliga frågeoperatorer
En viktig egenskap hos standardfrågeoperatorerna är att de implementeras som rena funktioner.
Mer information finns i Översikt över vanliga frågeoperatorer (C#) och Översikt över standardfrågasoperatorer (Visual Basic).