Оптимизация кода для получения чистых функций
Важным аспектом чисто функциональных преобразований является освоение способов оптимизации существующего кода для получения чистых функций.
Примечание
Общим подходом к функциональному программированию является оптимизация кода программ для получения чистых функций.В Visual Basic и C++ это равносильно использованию функций.Но в C# функции называются методами.В данном случае чистая функция в C# реализуется как метод.
Как отмечалось ранее в этом разделе, чистые функции имеют две полезные характеристики.
У них отсутствуют побочные эффекты. Функции не изменяют значения или данные любого типа, не входящие в область их определения.
Функции действуют единообразно. После получения того же набора входных данных они всегда возвращают одно и то же выходное значение.
Одним из способов перехода к функциональному программированию является оптимизация существующего кода с целью устранения ненужных побочных эффектов и внешних зависимостей. Таким образом, из существующего кода создаются чистые функции.
В этом разделе объясняется, что представляет собой чистая функция и чем она не является. В учебнике Управление данными в документе WordprocessingML показано управление документом WordprocessingML, содержится два примера оптимизации кода с помощью чистых функций.
Устранение побочных эффектов и внешних зависимостей
В следующих примерах сравниваются обычные и чистые функции.
Обычная функция, изменяющая член класса
В следующем примере кода функция HypenatedConcat представляет собой обычную функцию, поскольку изменяет элемент данных aMember в классе.
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
Этот код выводит следующие результаты.
StringOne-StringTwo
Обратите внимание, что неважно, какой доступ имеют изменяемые данные, public или private, и являются ли они членом класса static (shared) или элементом экземпляра. Чистая функция не изменяет не относящиеся к ней данные.
Обычная функция, изменяющая аргумент
Более того, следующая версия той же функции представляет собой обычную функцию, поскольку изменяет содержимое своего параметра sb.
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
Эта версия программы дает те же выходные данные, что и первая версия, поскольку функция HypenatedConcat изменила значение (состояние) своего первого параметра, вызвав функцию-член Append. Обратите внимание, что это изменение происходит несмотря на то, что функция HypenatedConcat использует передачу параметра по значению.
Важно!
Передача параметров по значению для ссылочных типов приводит к созданию копии ссылки на передаваемый объект.Эта копия все еще связана с теми же данными экземпляра, что и первоначальная ссылка (пока ссылочная переменная не будет присвоена новому объекту).Вызов по значению необязательно требуется функции для изменения параметра.
Чистая функция
Следующая версия этой программы реализует функцию HypenatedConcat в виде чистой функции.
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
И снова она дает ту же строку вывода: StringOne-StringTwo. Обратите внимание, что для сохранения соединенного значения оно сохраняется в промежуточной переменной s2.
Одним из полезных подходов является написание функций, которые локально являются обычными (то есть в них объявляются и изменяются локальные переменные), но глобально остаются чистыми. Такие функции имеют многие характеристики, благоприятные с точки зрения компоновки, но позволяют обойтись без использования некоторых более сложных средств функционального программирования, тех, что диктуют, например, необходимость использовать рекурсию, невзирая на возможность добиться того же результата с помощью простого цикла.
Стандартные операторы запроса
Важной характеристикой стандартных операторов запросов является то, что они реализуются как чистые функции.
Дополнительные сведения см. в разделе Общие сведения о стандартных операторах запроса.