2010-05-31

Парадигмы программирования, followup

Полтора года назад написал про парадигмы программирования. Сейчас подумал, что нужно называть вещи своими именами, а не так, как принято. :)

Например, функциональный язык — это такой, где вы будете задачи решать через функции. Т.е., когда вы беретесь за новую задачу, то напишите какой-нибудь defun или function. Следующим ключевым свойством функциональных языков является вот что: все есть выражение (expression), т.е. возвращает значение, а не утверждение (statement). Всё. На этом функциональность, строго говоря заканчивается. Но есть еще очень много других видов языков. Вот Haskell, например, язык, вообще говоря, не такой уже функциональный язык. Потому что решать вы все будете через типы и напишите сначала Data :: Type. А функции — лтшь один из частных случаев этих типов (один из типов, попросту говоря), но ведь гораздо интереснее такие типы, как монады или функторы. В общем, язык, на самом деле, алгебраический, т.е. для математиков (по складу ума). Вообще, все языки более-менее для кого-то там по складу ума.

Далее, вот, Common Lisp — наполовину функциональный, наполовину декларативный (потому что в половине случаев я начну не с defun, а с defmacro). А еще на треть объектно-ориентированный, потому что для defclass тоже часто найдется место (но без фанатизма). А Scheme — действительно чисто функциональный, так кроме функций больше ничего нет. Дальше посмотрим на Erlang — это сперва язык для конкурентного программирования. Всё закручено вокруг процессов и обмена сообщениями между ними. Это только на поверхности там пролог и функции, это всего лишь синтаксис. Т.е. нельзя отрицать функциональную ориентированность Erlang'а, но язык таки process-oriented/message-passing. А что же этот знаменитый функциональный язык JavaScript? Нет, нет и нет: "всё — выражение" не выполняется, и хотя функции — обычный синтаксис для записи кода, но ядро языка — это события и коллбеки, event-driven, как говорят американцы.

Возьмем теперь Ruby. Тут всё на классах и лямбдах, т.е. анонимных функциях. А обычные функции превращены в сообщения. Да еще и всё — выражение. Вот такая анархия или мультипарадигменность. И ко всему прочему полный контроль у программиста. Получается объектно-procедурно-немного декларативно-ориентированный. Еще есть Python. Тут все немного (или намного) регулярней. Есть классы и функции, но не всё выражение, анонимных функций, считай нет. В общем, glorified C (как хорошо показывет пример Cython), но, главное, что динамический и разумно простой. Современный объектно-ориентированный процедурный язык, в общем.

C Java, например, всё понятно. Тут чистый классовый подход. Класс на inner классе сидит и анонимным классом погоняет. Говорят, это называется объектно-ориентированный подход, хотя это, вообще-то, про Smalltalk или даже про Python. А тут у нас класс-ориентированный, чистой воды. На закуску остается C++, которому можно всё, особенно в версиях Boost и 0x. Только вот, забывают заметить, что это 3 отдельных языка: С, ++, а также еще Tempaltes. И это не говоря про препроцессор. Тут тоже, как бы, всё class-based, но всё — не объект, а указатель. Короче говоря, такой машинно-ориентированный язык с системами типов и классов, в придачу к возможности застрелить себя в ступню, как говорят опять же американцы...

Про brainfuck и все остальное более-менее без изменений.

12 comments:

Alex Ott said...

ээээ - а макросы в схеме куда делись?
P.S. лисп он еще и императивный

Vsevolod Dyomkin said...

@Alex, это так, рвздумия над тем, что самое first-class в языке, как принято решать задачи. И довольно субъективные, я бы сказал.

Есть, конечно, макросы в Схеме, только их совсем не так активно используют, мне кажется. (Хотя не могу судить объективно, поскольку смотрю только на код в интернетах, а не на github'ах и реальных проектах).

А на счет императивности Lisp'а. Ну, в общем-то любой язык, где прописывается какая-то последовательность действий (т.е. не Пролог), в той или иной степени императивный. Но, как по мне, в CL как раз императивность совсем не чувствуется, поскольку все возвращает значение, и значит все можно передавать в функции высших поярдков (вот как раз ключевая особенность функциональных языков, о чем я и написал, а не немутируемые переменные, например, или повсеместная рекурсия). Сейчас, по моим наблюдениям, почти никто (кроме новичков) не пишет на Lisp'е в стиле: взять то, положить сюда и т.п. Т.е. так задачи сейчас решать не принято. И даже всякие вещи, типа loop'а — довольно декларативные, хотя да, не без душка императивности...

Pencioner said...

А есть еще такой язык(и) (un)icon. sequence-ориентированный :)

Vsevolod Dyomkin said...

@pencioner да полно всего есть, я тут написал только о том, что в моей орбите интересов находится

rmrfchik said...

Scheme вовсе не чисто функциональный.
Недостаточно "всё делать через функции". Необходимо ещё зафиксировать понятие "функция". И если это сделать так, как это сделано в функциональных языках, то выяснится, что set! вовсе и не функция.

Vsevolod Dyomkin said...

@rmrfchik главное, что set! — это выражение и оно возвращает значение (попутно выполняя какие-то действия), в отличии от инструкции, которая ничего не возвращает. В математическом понимании — это, конечно, вовсе не функция, но это имеет гораздо меньшее значение для прагматики программирования.

rmrfchik said...

То, что set! попутно что-то делает имеет самые драматические последствия для функциональной прагматики программирования. Побочные эффекты или их отсутствие это ключевой момент функционального программирования. И отмахиваться от них несколько неосторожно.

Vsevolod Dyomkin said...

@rmrfchik это как раз и был пост о неправильных именах. Или, если зайти с другой стороны: полное отсутствие состояния — это фикция. Нет ни оной программы в таком вакууме. Вопрос только в том, каким образом представляется состояние и какой к нему интерфейс. Есть понятие ссылочной целостности, которое гораздо более практично: если вы даете на вхо они и те же значения, то получите одни и те же значения на выходе. Но вопрос в том, что такое значение и как оно соотносится с понятием состояния? Об этом есть хорошее эссе у Рича Хики: http://clojure.org/state

PS. Кстати, set! то как раз соблюдает ссылочную целостность... ;)

rmrfchik said...

set! может и соблюдает, не соблюдают те, кто set! использует.

Vsevolod Dyomkin said...

@rmrfchik это не обязательно и всецело зависит от программиста

rmrfchik said...

Это не должно зависеть от программиста.
Если математик видит в формуле знак "+", то вполне уверен в его значении.
К формулам не применяют "это зависит от автора формулы".
Есть определённые термины и понятия, есть базис который позволяет программистам общаться на одном языке.
Функциональные программисты оперируют понятием побочный эффект.
И, если вдруг приходит программист, который начинает в схеме использовать "set!" и при этом соблюдать (непонятную мне пока) "ссылочную целостность", то это плохой, негодный программист, т.к. использует инструмент (set!) не по делу.

Vsevolod Dyomkin said...

@rmrfchik Ну, вот видите, у Вас математический склад ума — Вам, наверно, больше всего подойдут алгебраические языки :)

> И, если вдруг приходит программист, который начинает в схеме использовать "set!" и при этом соблюдать (непонятную мне пока) "ссылочную целостность", то это плохой, негодный программист, т.к. использует инструмент (set!) не по делу.
Подождите, а как тога по делу? Не соблюдая ссылочной целостности?

Но если поправить это утверждение, то Вы тут сказали примерно то, что и я. Т.е. можно использовать set! по делу, и тогда Scheme будет вполне себе функциональным языком, а можно не по делу — и будет императивным. Идиоматический способ использования — я думаю, Вы не будете спорить, безусловно, функциональный...