Функциональное программирование |
Функциональное программирование всегда привлекало меня в противопоставлении к императивному.
Я очень часто обсуждаю различные аспекты функционального программирования на различных ветках на Базарной площади.
Но хотелось бы собрать всех заинтересованный этой темой в одной ветке.
Я думаю что настало время открыть такую тему. И вот почему.
Исторически функциональное программирование появилось практически вместе с императивным.
Вторым языком после фортрана был лисп.
Но увы, функциональное программирование надолго было уделом исследовательских институтов или специализированных приложений (Искусственный Интеллект)
Конечно не надо считать весь мир дураками из за того что развитие пошло по пути языков Алгол семейства.
Для этого были вполне обьективные причины. Функциональные языки слишком близки к человеку и слишком далеки от машины.
Они сьедают в десятки раз больше рессурсов чем императивные языки.
Вспомните претензии, предявляемые к java - первому императивному языку с виртуальной машиной и сборщиком мусора, толкаемому большими корпорациями в mainstream.
Жутко тормозит, и жрет всю память какая есть. А ведь функциональные языки (далее ФЯ) все без иключения имеют сборщик мусора, виртуальную машину.
Многие из них (семейство лисп) еще и динамические, что только усугубляет положение.
Вполне естественно что появившись более полусотни лет назад они надолго опередилли свое время.
Для широкого распространения ФЯ нужны гигабайты дешевой памяти и гигагерцы дешевых процессоров.
Прошло более 50 лет, прежде чем такие требования к железу стали реальностью.
Это время наступило. СЕЙЧАС.
Добро пожаловать в новую эру программирования.
Jack Of Shadows
Всего в теме 5502 сообщения
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Сравнение компиляторов
- Вот и вышла Delphi 7... Вы рады?
№ 92 11-06-2006 22:11 | |
Ответ на »сообщение 88« (Руслан Богатырев)
___________________________
Руслан спасибо за великолепное, простое и короткое обьяснение разницы между функциональным и императивным программированием.
Я пытался это сделать в нескольких постах, упоминая про изменение состояния, и обьясняя что функциональный код не имеет жестко заданной последовательности именно потому что не изменяет состояние системы.
Но вы это сделали гораздо лучше моих косноязычных попыток.
В случае ООП нельзя говорить об его императивности.
А вот тут вы неправы. Обьекты как контейнеры хранения данных (т.е. состояния системы), изменяющихся во времени, являются эссенцией императивного программирования. Они просто кричат "Я долговременное хранилище!, Ты должен менять данные во мне."
Обекты и функции это как вода и масло. Делать методы обьекты чистыми функциями, которые не меняют состояние обьекта, и возвращают результат, зависящий только от передаваемых им параметров - бессмысленно.
Такая функция просто не принадлежит никому конретно.
Обьекты с такими функциями часто встречаются в java, потому что там ОО доведен до идиотизма. Нельзя иметь отдельные функции, только лишь как методы обектов.
Поэтому народ просто обманывает систему запихивая все функции общего назначения в один класс в виде статических методов, как в контейнер, потому что другого способа написать такие функции у них просто нет - отобрали :))
Вот почему ООП относительно легко можно "прикрутить" к языкам, типичным для разных парадигм (императивное, функциональное, логическое и др.).
ООП нельзя прикрутить ни к чему. Он императивен до основания. Тот факт что ООП есть в таких языках как лисп или OCAML означает всего лишь то что лисп и OCAML это полноценные императивные языки, не более не менее.
Их называют функциональными только потому что они полностью поддерживают и функциональную парадигму.
Более точнее было бы называть такие языки не функциональными а multi-paradigm language. Увы не знаю как это сказать по русски :))
№ 91 11-06-2006 21:13 | |
Ответ на »сообщение 86« (Комбриг)
___________________________
Порядок операторов и вычислений функций может быть неважен тоже только в частных случаях. И просто не представляю себе более-менее сложный алгоритм, в котором не было бы частей, зависящих от результатов обработки других частей.
В этом беда всех императивных программистов. На самом деле любая программная система состоит их двух частей. Описание частей системы и их взаимосвязей (декларативная, функциональная часть). И часть системы выполняющая работу (изменяющяя состояние).
Так вот даже в самой маленькой системе декларативная часть занимает не менее 50%.
Система становится сложнее и больше от того что в ней больше частей и больще взаимосвязей между ними. Не от того что система выполняет большее количество инструкций. В больщих системах декларативная часть занимает практически весь код (80-90%)
Но программисту привыкшему давать компьютеру инструкции - невдомек. Он на самом деле, вполне серьезно так удивляется, откуда там может быть описательная часть. Ведь он ДАЕТ ИНСТРУКЦИИ. Они же зависят друг от друга.
Конечно зависят :))) Ведь ОПИСАТЬ СИСТЕМУ он не может. Язык не позволяет. :)))
Получается у него в коде практически НЕТ ФУНКЦИЙ. Т.е. нет функций возвращаемый результат которых зависит только от принимаемых параметров. Не функций которые кроме возвращения результата никак не влияют на состоянии системы.
Вот нам только что Комбриг заявил что просто не представляет себе такой код.
Это бы ло бы смешно, если бы это не было так ужасно. Если бы речь шла о несокльких программистах, а не о нескольких ПОКОЛЕНИЯХ программистов. Подавляющее большинство которых на полном серьезе думают что в коде если и есть декларативная часть то "только в частных случаях" т.е. где то 1-2%. А все остальное это значит "Алгоритм", с большой такой буквы.
К счастью времена когда можно было полностью игнорировать функциональные принципы построения программ и при этом именоваться профессиональным программистом, проходят.
Завтра функциональное программирование не только станет частью мейнстирма, Оно станет главной ее частью, тем что и будет именоваться программированием.
№ 90 11-06-2006 14:13 | |
Ответ на »сообщение 83« (info21)
___________________________
А компактность лисповской программы прямо связана с ее нечитабельностью.
Says who ? Для меня короткий лисп код гораздо читабельнее аналогичного по результату двухстраничного набора инструкций в жестко заданной последовательности. Вмето того чтобы продираться через все эти инструкции с целью понять чего же это программа делает, просто читаешь в лиспе ЗАДЕКЛАРИРОВАННУЮ функциональность.
Тут уже кажды должен решать для себя, что ему удобнее читать.
У программистов, знакомых не понаслышке с функциональным подходом есть преимущество. Они могут об этом судить.
Те же кто всю жизнь писал в императивном стиле, вынуждены верить заявлениям всяких гуру.
Я призываю всех заинтересованных в 'ndtnt на этот вопрос - не верьте ни мне ни infor21.
Попробуйте сами.
№ 89 11-06-2006 14:04 | |
Ответ на »сообщение 82« (Geo)
___________________________
Но вот сумму имеет смысл подсчитывать только после того, как все квадраты получены. Но никак не раньше.
Во первых время все равно сэкономлено. Даже если последняя операция ожидает завершения всех остальных.
Во вторых необязательно ждать, можно суммировать по мере поступления результатов остальных операций.
№ 88 11-06-2006 05:24 | |
В основе императивного подхода, как известно, лежат состояния (states) и операторы (statements). Последовательность операторов, приводящая к изменениям состояния программы, -- это ключевая особенность императивного программирования. Исполняется строго в том порядке, как записывается в программе!
В функциональном программировании основу составляют функции (functions) и их композиция. При этом важно не то, что здесь отсутствуют операторы и состояния (они просто скрыты). Важно то, что нет директивной последовательности выполнения. Т.е. то, что написано в тексте программы, не является обязательной (императивной) командой (директивой) ее выполнения ровно в таком же порядке. Собственно этого ответа я и ждал от Jack of Shadows, когда спрашивал, чего же такого не хватает в императивном программировании, когда функции того же Лиспа в лоб имитируются процедурами/функциями Оберона (императивного языка, который не является языком ООП).
В случае ООП нельзя говорить об его императивности. Ведь в основе ООП лежит посылка сообщений, которые динамически связываются с методами, осуществляющими выполнение программы. Эта посылка может выполняться как синхронно (в жестком порядке), так и асинхронно (ограничения на “хаос”). Вот почему ООП относительно легко можно "прикрутить" к языкам, типичным для разных парадигм (императивное, функциональное, логическое и др.). И вот почему при сопоставлении функционального и императивного подходов не совсем корректно сравнивать функции Лиспа с объектами.
№ 87 11-06-2006 02:46 | |
Ответ на »сообщение 86« (Комбриг)
___________________________
Вот ИМХО в этом-то все и дело. Порядок операторов и вычислений функций может быть неважен тоже только в частных случаях. И просто не представляю себе более-менее сложный алгоритм, в котором не было бы частей, зависящих от результатов обработки других частей. Есть конечно, немало задач, которые требуют просто большого числа одинаковых действий над независимыми данными, но такие задачи великолепно распараллеливались еще во времена моей молодости, на ФОРТРАНЕ...
c=d
f(a(с), b())
в имеративном языке означает "сначала выполнить присваивание c=d, потом вычислить a() потом b() потом вычислить f() от аргуметов"
а в функциональном
"результат должен равняться результату вычисления функции f относительно a(c) и b() и меня не волнует что и в каком порядке ты будешь делать"
например если f имеет такой вид:
f(x,y)=если x>5 то x иначе y
то y может вообще не вычисляться
таким образом имеративная семантика содержит больше зависимостей чем рекльно нужно по задаче
№ 86 11-06-2006 00:03 | |
Ответ на »сообщение 82« (Geo)
___________________________
Ответ на »сообщение 81« (Комбриг)
___________________________
Пока нет Вагифа, попробую ответить я (в меру моего понимания).
Как я понял, при функциональном программировании порядок выполнения операторов не важен. Соответственно, любой код может быть распараллелен не думая на любое количество процессов (хоть по оператору на процесс). При императивном программировании в общем случае последовательность выполнения операторов важна...
Вопрос Вагифу.
Так как я не знаю ни Лиспа, ни Хаскеля, ни иже с ними, то буду ориентироваться на Excel (если можно). Допустим, у нас есть колонка чисел (ну, или список в Лиспе, хотя, думаю, Вам мой перевод не требуется :-) Нужно получить сумму квадаратов этих чисел. Действительно, какое число возводить в квадрат сначала, какое потом -- это абсолютно не важно, и вычисление квадратов может быть без проблемм распараллелено. Но вот сумму имеет смысл подсчитывать только после того, как все квадраты получены. Но никак не раньше...
Вот ИМХО в этом-то все и дело. Порядок операторов и вычислений функций может быть неважен тоже только в частных случаях. И просто не представляю себе более-менее сложный алгоритм, в котором не было бы частей, зависящих от результатов обработки других частей. Есть конечно, немало задач, которые требуют просто большого числа одинаковых действий над независимыми данными, но такие задачи великолепно распараллеливались еще во времена моей молодости, на ФОРТРАНЕ...
Если речь просто идет о том, что «вместо явных инструкций о создании новых процессов и их взаимодействии и синхронизации, код обрамляется инструкциями о выборе стратегии распараллеливания. Код внутри такого блока распараллеливается автоматически в соответствии с выбранной стратегией» , то я опять не вижу, почему в императивных языках это будет работать хуже. Тем более, что как верно заметил info21, «Сравнивать функции Лиспа нужно не с процедурами Оберона и т.п., а с оъектами. Тогда все становится на свои места: никаких принципиальных преимуществ функц. языки не дают.» . Добавлю только, что аналогично будет с объектами Delph или C#.
№ 84 10-06-2006 13:00 | |
Ответ на »сообщение 79« (Trurl)
___________________________
Пока функциональные языки хорошо распараллеливаются только теоретически.
Согласен. Теоретически функциональный код легко распараллеливается.
На практике же нужно для этого написать компилятор. А механика распараллеливания сильно зависит от архитектуры многопроцессороной системы. Что это ? Несколько процессоров в одной машине ? Или один процессор со многими ядрами ? Или распределенная сеть машин ? Как осуществляется взаимодействие процессоров ? shared cache architecture ? или message passing ?
Все это принципиально влияет на то как будет писаться конкретный компилятор, распараллеливающий код.
В виду того что многопроцессорные системы до недавнего времени были в исчезаюзем меньшинстве, работы по неявному распараллеливванию не получали должного внимания, интереса и финансирования.
Однако в последние годы ситуация резко изменилась.
Реально распараллеливаются программы на языках, специально разработанных под это дело. Как правило, эти языки содержат специальные конструкции для параллельных вычислений, что роднит их с императивными языками аналогичного назначаеия.
http://cs.anu.edu.au/ample/ - Эекпериментальная среда Ample написанная на хаскеле. Принимает любой хаскель код и распараллеливает его, без всяких явных инструкций в коде.
http://www.cashncarrion.co.uk/products/1022/0 - pH экспериментальный язык, на базе хаскеля, полностью поддерживающий неявное распараллеливание (implicit parallelism).
http://www.cs.ncl.ac.uk/research/projects/detail.php?id=53 - Newcastle Parallel Machine разработка архитектуры компьютера на котором функциональный код автоматически распараллеливается.
http://www.cse.unsw.edu.au/~chak/project/dph/ - Data Parallel Haskell - Расширение хаскеля для автоматического распараллеливания.
Кроме того работы еще ведутся в другом направлении, не автоматическое распараллеливание а скажем так, полу-автоматическое. :))
Т.е. вместо явных инструкций о создании новых процессов и их взаимодействии и синхронизации, код обрамляется инструкциями о выборе стратегии распараллеливания. Код внутри такого блока распараллеливается автоматически в соответствии с выбранной стратегией.
Заметьте что все эти работы ведутся только с функциональным кодом. Императивным программам там ловить нечего.
Как видите наблюдается буквально взрывной рост работ в направлении автоматизации распараллеливания.
И все эти работы крутятся в основном вокруг хаскеля (иногда и SML)
Напоследок подкину вам интересную статью
The Free Lunch Is Over: A Fundamental Turn Toward Concurrency in Software
http://www.gotw.ca/publications/concurrency-ddj.htm
Там говорится о том же самом о чем мы здесь с вами ведем речь, только покрасивше и на английском.
Все, мне пора бежать. Уикенд, шашлыки, пиво на природе. :))
№ 83 10-06-2006 08:53 | |
Сравнивать функции Лиспа нужно не с процедурами Оберона и т.п., а с оъектами.
Тогда все становится на свои места: никаких принципиальных преимуществ функц. языки не дают.
А компактность лисповской программы прямо связана с ее нечитабельностью.
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|