Функциональное вычисление – функция (или если быть точнее – «чистая функция», pure function) – должна принимать некоторые аргументы (входящие данные) на входе, производить вычисление и возвращать некоторый результат. При этом функция не должна создавать никаких побочных эффектов... В общем, функция не имеет право делать ничего, что могло бы изменить состояние чего бы то ни было. Все, что может сделать функция – это произвести вычисления и выдать результат.
DM>У такого подхода есть одна замечательная особенность. Функция всегда должна возвращать один и тот же результат для одних и тех же аргументов.
DM>Если это следствие перечисленного, то неверно, когда функция может читать изменяемые данные (глобальные или в замыкании).
Слона выделенного жирным ты не заметил?
Прочти еще раз, только по внимательнее то что написано в статье. Чистая функция не может обладать побочными эффектами, а стало быть не может читать никакие глобальные данные. Не то что изменяемые. И замыкаться на изменяемые денные она тоже не должна. Иначе она не чистая функция.
DM>
ФЯ развивают эту идею, возводя ее в принцип – функция является в программе таким же полноценным объектом, как и экземпляр любого другого типа (например, экземпляр строки).
DM>Сразу вопросы: можно ли функции сравнивать на равенство?
Можно. Но будут сравниваться только ссылки, когда как с точки зрения теории функции равны при условии, что они возвращают одинаковый результат для всего множества возможных входных значений. К сожалению задача проверки подобного условия на практике не разрешима. Но и сравнение по ссылке иногда полезно.
DM>Можно ли их сериализовать в файл?
Потенциально — да, но на практике этого никто не делает, так как это лишено смысла. Сериализация не является обязательной для того чтобы что-то можно было признать первоклассным объектом.
DM>Вычислять хэш?
Конечно можно. Только опять же хэш будет идентичен для одинаковых ссылок.
DM>Если нет, то не такие уж и полноценные объекты. Если да, возможно, стоит об этом упомянуть.
Все что нужно для признания функций первокласными объектами я привел. Это не мои измышления, а проверенная практикой теория. Если хочется с ней поспорить, то без меня, плиз.
DM>
Скажем, в С мы можем передать указатель на функцию другой функции, но составить из двух функций третью мы не в силах.
DM>
DM>typedef int (*func)(int);
DM>int compose(func a, func b, int x)
DM>{
DM> return a(b(x));
DM>}
DM>
Где здесь образована новая функция? Это статически описанная функция принимающая два указателя на функции.
Если бы С поддерживало бы создание функций из других функций, то в нем было бы можно написать такой код:
typedef int (*func)(int);
func compose(func a, func b)
{
return a + b;
}
func f3 = compose(f1, f2);
f3(2);
DM>
Первое, что требуется для манипуляции функциями – это иметь возможность описать их тип.
DM>Неверно, если речь про ФЯ в целом. Как-то Лисп без этого обошелся.
Согласен. Это утверждение корректно только для статически типизированных языков коим и является C#. Поправлю.
Спасибо.
DM>И пара опечаток: DM>
arg1 => arg2.ToString()
DM>
СПИСОК_ПОЛЕ_ПЕРЕЧИСЛЕННЫХ_ЧЕРЕЗ_ЗАПЯТУЮ
Спасибо. Поправлю.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re: LINQ как шаг к функциональному программированию
Спасибо. Хорошая статья.
Понравилось, что статья, ориентированная на начинающих, написана простым языком.
Маленькое дополнение — хорошо бы указывать набор ПО, необходимый для того, чтобы воспроизвести данные примеры. Например, номер фреймворка, версию студии и т.д.
Кстати, я правильно понимаю, что в Mono эти возможности пока не реализованы?
Re: LINQ как шаг к функциональному программированию
Материал актуален и интересен, но статья очень сырая:
— Много ошибок разного характера.
— Стиль изложения ни куда негодится, читать очень сложно. Изложение текста должно быть "бесстрасным", а сейвас все выглядит, как попытка показать свое превосходство.
Реккомендация:
— Вычитывать материал несколько раз. Через день другой прочитать еще раз
— Давать читать другим перед публикацией и осмысливать критику
--
То, что вы уникальны еще не значит, что от вас есть толк
Re[2]: LINQ как шаг к функциональному программированию
Здравствуйте, DemAS, Вы писали:
DAS>Понравилось, что статья, ориентированная на начинающих, написана простым языком. DAS>Маленькое дополнение — хорошо бы указывать набор ПО, необходимый для того, чтобы воспроизвести данные примеры. Например, номер фреймворка, версию студии и т.д.
ОК. Учту.
DAS>Кстати, я правильно понимаю, что в Mono эти возможности пока не реализованы?
Гарантировать ничего не могу, так как с Моно не занимаюсь. Но вроде как должно работать. Моно вообще довольно живенько за МС бежит.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: LINQ как шаг к функциональному программированию
Здравствуйте, VladD2, Вы писали:
VD>Ты тут споришь черт знает о чем, а главной сути статьи так и не понял. Ее суть подвигнуть людей мыслить функционально. Ты же четко демонстрируешь императивное мышление и вместо того чтобы попробовать изменить свои взгляды ввязываешся во флэймы о пользе и вреде явной аннотации типов.
А причем здесь статья? Сергей Суханов обратил внимание, что в реализации Aggregate от MS разложены грабли, соответственно эти грабли в данной подветке и обсуждаются.
Что касается твоей статьи, то она толковая, существенных претензий у меня к ней нет.
U>>Что есть ужас.
VD>Ужас в твоей голове. Шарп конечно не лучший ФП язык и его библиотеки не очень чисты, но тем не менее и на нем можно писать вполне себе функционально.
VD>
И что от того, что ты использовал запись в одну строчку, необходимость явной записи условия куда-то делась? Необходимость явной записи условия при использовании библиотечной функции это ужас.
VD>Если говорить о решении конкретной задачи — преобразовании последовательности в строку, то грамотным решением будет создание специализированных функций вроде: VD>
И каким образом полноценный string.Join устранит грабли при использовании Aggregate?
VD>К сожалению именно этого ты и не увидел. Зато усмотрел проблемы у МС. Меж тем в большинстве ФЯ вообще нет аналога Aggregate не принимающего начальное значение. Так что это своего рода расширение.
Потому что в большинстве ФЯ решили не добавлять библиотечную функцию с заботливо разложенными граблями, в MS же не додумали. В то время как достаточно было вместо Aggregate(Func<T, T, T> func) сделать такую перегрузку:
Aggregate(Func<T, T, T> func, T defaultValue)
Такая перегрузка позволила бы прозрачным образом обрабатывать и пустую коллекцию и отсутствие коллекции(null).
Re[7]: LINQ как шаг к функциональному программированию
Здравствуйте, Undying, Вы писали:
U>И каким образом полноценный string.Join устранит грабли при использовании Aggregate? VD>>К сожалению именно этого ты и не увидел. Зато усмотрел проблемы у МС. Меж тем в большинстве ФЯ вообще нет аналога Aggregate не принимающего начальное значение. Так что это своего рода расширение. U>Потому что в большинстве ФЯ решили не добавлять библиотечную функцию с заботливо разложенными граблями, в MS же не додумали. В то время как достаточно было вместо Aggregate(Func<T, T, T> func) сделать такую перегрузку:
U>Aggregate(Func<T, T, T> func, T defaultValue)
U>Такая перегрузка позволила бы прозрачным образом обрабатывать и пустую коллекцию и отсутствие коллекции(null).
Такая перегрузка
public static TAccumulate Aggregate<TSource, TAccumulate>(
this IEnumerable<TSource> source,
TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func
)
Это разные перегрузки. Seed участвует в агрегации, а это не всегда нужно, например, string.Join на перегрузке с seed реализовать нельзя. А defaultValue в агрегации не участвует, оно просто возвращается если данных для агрегации недостаточно (т.е. коллекция пуста или равна null).
Re[9]: LINQ как шаг к функциональному программированию
Здравствуйте, Undying, Вы писали:
_FR>>Такая перегрузка
… U>Это разные перегрузки. Seed участвует в агрегации, а это не всегда нужно, например, string.Join на перегрузке с seed реализовать нельзя.
Здравствуйте, _FRED_, Вы писали:
U>>Это разные перегрузки. Seed участвует в агрегации, а это не всегда нужно, например, string.Join на перегрузке с seed реализовать нельзя.
_FR>Можно _FR>
_FR>Func<IEnumerable<string>, string> join = x => x.Skip(1).Aggregate(x.FirstOrDefault(), (y, z) => y + ", " + z);
_FR>
Шаман, однако. Надеюсь в реальных проектах ты так не пишешь?
Re[11]: LINQ как шаг к функциональному программированию
U>И что от того, что ты использовал запись в одну строчку, необходимость явной записи условия куда-то делась? Необходимость явной записи условия при использовании библиотечной функции это ужас.
Я понимаю людей которые писали этот метод. Совершено не ясно где взять значение для пустого списка. Они ведь не телепаты. Возможно было бы неплохо написать перегрузку принимающую дефолтное значение. Но это не трудно сделать и сейчас.
VD>>Если говорить о решении конкретной задачи — преобразовании последовательности в строку, то грамотным решением будет создание специализированных функций вроде: VD>>
U>И каким образом полноценный string.Join устранит грабли при использовании Aggregate?
Я наверно потерял нить. О чем речь? Причем тут string.Join?
U>Потому что в большинстве ФЯ решили не добавлять библиотечную функцию с заботливо разложенными граблями, в MS же не додумали. В то время как достаточно было вместо Aggregate(Func<T, T, T> func) сделать такую перегрузку:
В ФЯ обычно списки являются встроенными типами которые реализуются на базе алгебраических типов данных. Их очень легко обрабатывать с помощью паттерн-матчинга и рекурсивных функций. В Шарпе этих фич нет, что приводит к необходимости иметь набор библиотечных функций.
U>
U>Aggregate(Func<T, T, T> func, T defaultValue)
U>
U>Такая перегрузка позволила бы прозрачным образом обрабатывать и пустую коллекцию и отсутствие коллекции(null).
Согласен. Ее не трудно написать на базе имеющейся функции.
Но конечно выбранное решение не очень хорошее.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[11]: LINQ как шаг к функциональному программированию
Здравствуйте, Undying, Вы писали:
_FR>>Можно _FR>>
_FR>>Func<IEnumerable<string>, string> join = x => x.Skip(1).Aggregate(x.FirstOrDefault(), (y, z) => y + ", " + z);
_FR>>
U>Шаман, однако. Надеюсь в реальных проектах ты так не пишешь?
Тут важно уловить сам подход. А потом ты сам напишешь несколько нужных тебе функций высшего порядка и будешь писать чисто, красиво и весьма эффективно.
Лично я конкатенирую строки так "..$список". Но это уже специализированный ДСЛ, что является следующим шагом на пути к декларативизации кода.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.