Сегодня на семинаре читался (кажется, шестикурсником) доклад про ФП. Как мне кажется, он был сделан крайне неудачно. Если докладчик и разбирался сам в предмете (в чём я не полностью уверен), то после его доклада уж точно никто разбираться не начал.
* Как был построен его доклад?
1) сначала Чёрч придумал лямбду; (тут идут длинные, туманные, и главное -- ненужные иллюстрации про лямбда-исчисление)
2) потом Маккарти придумал Лисп, и началось ФП. Все ЯП делятся на низкоуровневые, процедурные+ОО (как одна категория) и функциональные. (Вопрос из зала: в какую из этих категорий отнести MSIL? он идеально попадает сразу в две.)
3) ФЯП много, но самый крутой -- это Хаскелл. Дальше до конца доклада разбираются примеры на Хаскелле в следующем формате: код на Хаскелле (компактный и абсолютно непроницаемый), аналогичный ему код на C# (громоздкий и неестественный), и комментарий "поверьте мне на слово, это работает". Пару опечаток в его непроницаемом коде мы всё-таки нашли.
* И какие выводы могла из всего этого сделать аудитория?
Что ФП -- это способ компактно и непроницаемо закодировать код на C#. Эдакий способ обфускации программ, вроде комплекта экзотических макросов с IOCCC.
Неудачен был даже сам заголовок доклада: "ФП как альтернатива ООП". ФП не отменяет ООП, а расширяет его -- точно так же, как ООП не отменило процедурное программирование. ФП и ООП могут прекрасно сочетаться -- в том же C#, например.
* Как бы этот доклад построил я? Я бы даже историю ФП ввёл по-другому.
1) сначала были низкоуровневые языки, и не было разделения на код и данные. С данными можно было работать как с кодом, и наоборот.
2) потом придумали Фортран, Алгол и так далее до Сей. Между кодом и данными возвели берлинскую стену: код -- это нечто универсальное и неизменное, а его поведение определяется переданными ему данными. Компиляторы даже кладут код и данные в разные секции исполняемого файла.
3) чтобы связать код и данные, придумали ООП. Теперь каждый кусок данных ("объект") имеет механически привязанный к себе код; этот код всё так же неизменен, но уже не универсален -- он может работать только с данными, к которым он привязан.
4) наконец, поняли, что можно считать функции, сами по себе, объектами; что код -- это один из видов данных. Что функции можно создавать, комбинировать и выполнять над ними всякие действия, как над любыми другими данными. Что можно даже дойти до крайности, и объявить функции единственным типом данных; и этого окажется достаточно для полноты по Тьюрингу. (Но никто в здравом уме не будет программировать в лямбда-исчислении без чисел и строк, также как никто в здравом уме не станет программировать таблицу переходов для машины Тьюринга.)
Потом я бы, если и стал приводить примеры кода, взял бы для этого что-нибудь максимально проницаемое (если Перл не устраивает, то хоть и тот же C#, или даже голый C++ с функторами), вместо того чтобы ошарашивать публику марсианскими иероглифами никому не понятных, но зато безмерно крутых языков. И постарался бы подобрать заранее задач, где ФП выгодно -- например, где берётся "срез" функции, или где результатом алгоритма является функция -- в общем, где требуется создать экземпляр функции. И именно на этом центральном для ФП понятии -- экземпляр функции -- заострял бы внимание, потому что это именно то, что ФП прибавляет к "традиционному" ООП. А не на отсутствии побочных эффектов (которые всё равно нужны, потому что окружение функциональной программы -- это реальный компьютер, который меняет со временем своё состояние, и для взаимодействия с этим окружением нужно уметь узнавать и изменять текущее состояние), и не на возможности ленивых вычислений (это вообще не специфика ФП, а одна из фишек его конкретного воплощения в Хаскелле).
В завершение я бы сказал, что ФП -- это не переворот в программировании, и что ФП можно применять в обычных программах на обычных языках -- потому что язык и способ программирования друг друга не предопределяют. Просто есть языки, специально под ФП заточенные, -- и в них это удобнее, чем в Перле, или в том же C#, и тем более в голом C++ с функторами. И может, показал бы какой-нибудь один пример кода на ФЯП -- хотя, в принципе, к чему это?