* Как я уже отмечал раньше, понятие "функция" по-разному трактуется в ФП и в традиционном процедурном программировании.
В Си и подобных ему языках функция -- это блок кода, выполнение (вызов) которого -- элементарная операция. Функция может принимать аргументы, может возвращать значение, но не обязана делать ни то, ни другое.
В ФП, как и в математике вообще, функция -- это сопоставление значению аргументов значения функции. Там функция не вызывается, а вычисляется. Если функция чистая, т.е. не имеет побочных эффектов, то компилятор может даже где-нибудь кешировать её значение. Функция, не принимающая аргументов, имеет весьма ограниченный смысл (это может быть Rnd, константа или что-нибудь в этом роде); функция, не возвращающая значения, не имеет смысла вовсе.
* В C# 3.0 будут функции обоих этих родов. Для объявления функций "в стиле ФП" добавится уйма шаблонов типа Func<...> и оператор =>, сопоставляющий функции её значение.
Эрик Липперт писал(а):Раньше [в C# 2.0], чтобы создать функцию, принимающую int и возвращающую функцию из int в int, нужно было делать что-то наподобие этого:
- Код: Выделить всё
delegate int D1(int y);
delegate D1 D2(int x);
//...
D2 makeAdder = delegate(int x){
return delegate(int y){
return x + y;
};
};
D1 addTen = makeAdder(10);
Console.WriteLine(addTen(20));
Теперь же [в C# 3.0] у нас в стандартной бибилиотеке будут такие объявления:
- Код: Выделить всё
delegate R Func<R>();
delegate R Func<A1, R>(A1 a1);
delegate R Func<A1, A2, R>(A1 a1, A2 a2);
delegate R Func<A1, A2, A3, R>(A1 a1, A2 a2, A3 a3);
//...и т.д., для любого разумного числа аргументов
Так что можно будет использовать их совместно с лямбдами [оператором =>], чтобы сделать наш код намного проще и прозрачнее:
- Код: Выделить всё
Func<int, Func<int, int>> makeAdder = x=>(y=>x+y); //скобки необязательны
Func<int, int> addTen = makeAdder(10);
Console.WriteLine(addTen(20));
Интересно, что не любой делегат, который можно было объявить со старым синтаксисом, можно будет объявить при помощи этих шаблонов. Очевидные примеры -- делегаты, возвращающие void, или имеющие параметры с модификаторами out или ref.
* Далее он отмечает, что новым способом нельзя объявить рекурсивные делегаты, в том числе самый функциональный из всех возможных делегатов -- функцию, принимающую аргументом функцию и возвращающую функцию, где каждая из этих функций сама принимает аргументом функцию и возвращает функцию:
- Код: Выделить всё
delegate D D(D d);
Такая функция называется комбинатором и образует основу всего лямбда-исчисления, основы ФП. То, что даже с новыми функциональными возможностями в C# 3.0 для использования основы основ ФП потребуется прибегать к "функциям в стиле Си" -- по меньшей мере, забавно.