Refaktoring do čistých funkcí (LINQ to XML)
Důležitým aspektem čistě funkčních transformací je naučit se refaktorovat kód pomocí čistých funkcí.
Poznámka:
Běžnou nomenklaturou funkčního programování je, že refaktorujete programy pomocí čistých funkcí. V jazyce Visual Basic a C++ je to v souladu s používáním funkcí v příslušných jazycích. V jazyce C# se však funkce nazývají metody. Pro účely této diskuze je čistá funkce implementována jako metoda v jazyce C#.
Jak jsme uvedli dříve v této části, čistá funkce má dvě užitečné vlastnosti:
- Nemá žádné vedlejší účinky. Funkce nemění žádné proměnné ani data jakéhokoli typu mimo funkci.
- Je konzistentní. Vzhledem ke stejné sadě vstupních dat se vždy vrátí stejná výstupní hodnota.
Jedním ze způsobů přechodu na funkční programování je refaktoring stávajícího kódu, který eliminuje zbytečné vedlejší účinky a externí závislosti. Tímto způsobem můžete vytvořit čisté verze funkce existujícího kódu.
Tento článek popisuje, co je čistá funkce a co ne. Kurz : Manipulace s obsahem v dokumentu WordprocessingML ukazuje, jak manipulovat s dokumentem WordprocessingML a obsahuje dva příklady refaktoringu pomocí čisté funkce.
Následující příklady kontrastuje se dvěma nečistými funkcemi a čistou funkcí.
Příklad: Implementace nečisté funkce, která změní člen statické třídy
V následujícím kódu HyphenatedConcat
není funkce čistá funkce, protože upravuje aMember
člen statické třídy:
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
Tento příklad vytvoří následující výstup:
StringOne-StringTwo
Mějte na paměti, že je irelevantní, jestli mají změněná public
data nebo private
přístup, nebo je static
členem, shared
členem nebo členem instance. Čistá funkce nemění žádná data mimo funkci.
Příklad: Implementace nečisté funkce, která změní parametr
Kromě toho následující verze této stejné funkce není čistá, protože upravuje obsah jeho parametru, 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
Tato verze programu vytvoří stejný výstup jako první verze, protože HyphenatedConcat
funkce změnila hodnotu (stav) prvního parametru Append vyvoláním členské funkce. Všimněte si, že k této změně dochází i přes skutečnost, že HyphenatedConcat
používá předávání parametru call-by-value.
Důležité
Pokud pro odkazové typy předáte parametr podle hodnoty, bude výsledkem kopie odkazu na předaný objekt. Tato kopie je stále přidružená ke stejným datům instance jako původní odkaz (dokud není referenční proměnná přiřazena k novému objektu). Volání podle odkazu nemusí nutně vyžadovat, aby funkce upravila parametr.
Příklad: Implementace čisté funkce
Tato další verze programu ukazuje, jak funkci implementovat HyphenatedConcat
jako čistou funkci.
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
Tato verze opět vytvoří stejný řádek výstupu: StringOne-StringTwo
. Mějte na paměti, že pokud chcete zachovat zřetězenou hodnotu, je uložena v zprostředkující proměnné s2
.
Jedním z přístupů, který může být velmi užitečný, je psát funkce, které jsou místně nečisté (tj. deklarují a upravují místní proměnné), ale jsou globálně čisté. Takové funkce mají mnoho z žádoucích vlastností kompozability, ale vyhněte se některým konvolutovaným funkčním programovacím idiomům, jako je třeba muset použít rekurzi, když jednoduchá smyčka dosáhne stejné věci.
Standardní operátory dotazů
Důležitou charakteristikou standardních operátorů dotazu je, že se implementují jako čisté funkce.
Další informace najdete v tématu Přehled operátorů standardních dotazů (C#) a Přehled operátorů standardních dotazů (Visual Basic).