Функциональное программирование |
Функциональное программирование всегда привлекало меня в противопоставлении к императивному.
Я очень часто обсуждаю различные аспекты функционального программирования на различных ветках на Базарной площади.
Но хотелось бы собрать всех заинтересованный этой темой в одной ветке.
Я думаю что настало время открыть такую тему. И вот почему.
Исторически функциональное программирование появилось практически вместе с императивным.
Вторым языком после фортрана был лисп.
Но увы, функциональное программирование надолго было уделом исследовательских институтов или специализированных приложений (Искусственный Интеллект)
Конечно не надо считать весь мир дураками из за того что развитие пошло по пути языков Алгол семейства.
Для этого были вполне обьективные причины. Функциональные языки слишком близки к человеку и слишком далеки от машины.
Они сьедают в десятки раз больше рессурсов чем императивные языки.
Вспомните претензии, предявляемые к java - первому императивному языку с виртуальной машиной и сборщиком мусора, толкаемому большими корпорациями в mainstream.
Жутко тормозит, и жрет всю память какая есть. А ведь функциональные языки (далее ФЯ) все без иключения имеют сборщик мусора, виртуальную машину.
Многие из них (семейство лисп) еще и динамические, что только усугубляет положение.
Вполне естественно что появившись более полусотни лет назад они надолго опередилли свое время.
Для широкого распространения ФЯ нужны гигабайты дешевой памяти и гигагерцы дешевых процессоров.
Прошло более 50 лет, прежде чем такие требования к железу стали реальностью.
Это время наступило. СЕЙЧАС.
Добро пожаловать в новую эру программирования.
Jack Of Shadows
Всего в теме 5502 сообщения
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Сравнение компиляторов
- Вот и вышла Delphi 7... Вы рады?
№ 3262 06-10-2007 10:16 | |
Ответ на »сообщение 3258« (Илья Ермаков)
___________________________
Достаточно часто в программе некоторая переменная (локальная, про глобальные вообще забудем) используется для хранения значения, которое вычисляется один раз, а используется несколько.
А почему забудем про глобальные переменные?
Если значение этой переменной вычисляется чистой функцией без побочных эффектов, то нет никаких оснований для неиспользования глобальных переменных кроме замусоривания пространства имён, которое ограничивается границами модуля...
Впрочем, если эта переменная вычисляется чистой функцией, то теоретически неважно, в скольких местах указывается её вычисление - компилятор может просто отследить все эти места и вычислить эту переменную один раз, а затем просто использовать это значение везде, где нужно...
В стиле ФП, чтобы обеспечить это повторное использование, придётся вводить промежуточную функцию, которая принимает это значение параметром?
Т.е. функция A считает один раз это значение, затем вызывает функцию AA, которая принимает это значение параметром и несколько раз его использует (передаёт каким-то другим функциям)?
Т.е. всё состояние концентрируется только в точке передачи параметра.
В чистом функциональном коде всё изменяемое состояние должно передаваться через параметры функций и возвращаться в качестве результатов функций.
Исключение - монадный ввод-вывод, там из функции в функцию ещё неявно передаётся "состояние мира", которое изменяется этими IO-функциями, что приводит к императиву...
Там (в монадном вводе-выводе) вапще нет у меня ещё ясного понимания - вроде и понимаю, что если рассахарить do-нотацию, то получится чистый функциональный код, но тут ещё надо учесть неявной пармаетр "состояние мира", это сбивает с толку и выглядит таки императивно... Так что приходится уговаривать себя в том, что сама программа функционально чиста, а мир... Ну мир он и есть мир - постоянно меняется от несчисленных причин, одна из которых моя программа, которая типа и не является частью этого мира... :о))
ЗЫ. Вапще-то приведите пример кода, который Вы имеете в виду, посмотрим, как это должно выглядеть в чистом ФП. Можете даже задействовать циклы и break'и, да хоть даже и yeald'ы, что бы ни было... ;о)
№ 3261 06-10-2007 09:43 | |
Ответ на »сообщение 3231« (Стэн)
___________________________
>>>Кстати без всяких явных break и return... И очень даже понятно...
А теперь представим, что в Haskell добавили return. Для удобства ;-)
hasItem a x = any map \y-> if (y == x) then break true else false
№ 3260 06-10-2007 09:38 | |
Ответ на »сообщение 3249« (Geniepro)
___________________________
List comprehensions не основаны на do-нотации и не имеют осношения к монадам. Это раз.
Монады в Хаскелле - это не просто классы. Это два.
Любой, даже не очень опытный функциональщик, легко реализует классы Monad и MonadPlus, но никакой опыт не поможет ему реализовать IO или ST. Это три.
Императив можно имитировать и без всяких монад. Это четыре.
№ 3259 06-10-2007 08:54 | |
Ответ на »сообщение 3255« (panda)
___________________________
Ответ на »сообщение 3254« (Илья Ермаков)
___________________________
Вы специально на языке с самым запутанным синтаксисом, чтобы было понятнее? Ну-ну...
Нет. Примеры были завязаны на foreach, т.е. заточены под идею "проход по перечислимым коллекциям". Чтобы показать отдельно алгоритмическую часть, не нарушая эквивалентности по общности (т.к. на Обероне я бы написал пример для конкретного массива, конкретного списка, но не обобщённо и спровоцировал бы совершенно к алгоритмике не относящиеся претензии), я выбрал то, чем владею - C++ STL, т.к. Питона и C#, на которых были написаны примеры, не знаю.
№ 3258 06-10-2007 08:26 | |
Вот вопрос к корифеям ФП.
Достаточно часто в программе некоторая переменная (локальная, про глобальные вообще забудем) используется для хранения значения, которое вычисляется один раз, а используется несколько.
В стиле ФП, чтобы обеспечить это повторное использование, придётся вводить промежуточную функцию, которая принимает это значение параметром?
Т.е. функция A считает один раз это значение, затем вызывает функцию AA, которая принимает это значение параметром и несколько раз его использует (передаёт каким-то другим функциям)?
Т.е. всё состояние концентрируется только в точке передачи параметра.
№ 3257 06-10-2007 07:57 | |
Ответ на »сообщение 3255« (panda)
___________________________
Ответ на »сообщение 3254« (Илья Ермаков)
В котором месте Ваш вариант понятнее моего?
Обоснование, почему мой вариант лучше (в принципиальном смысле), я уже назвал - »сообщение 3227«.
Я понимаю, если бы были возвражения характера "принцип принципом, но вот же конкретный случай, где с "goto" читается лучше". Однако код получился полностью идентичный, и по краткости, и по простоте восприятия.
Поэтому, есть в науке такое понятие - "бремя доказательства". Чтобы доказать, что целесообразно где-то пренебречь принципиальными преимуществами всегда использовать циклы с одним выходом, построенного на основе постусловия, именно Вы должны приводить чёткие и реально встречающиеся примеры, где отход от этого принципа даст заметное сокращение кода и "понимабельность". Все приведённые примеры были действительно реальными, из практики - и все они прекрасно переписались в чистом стиле без какого-либо удлиннения кода.
Фактически, по структурным единицам, код стал даже короче - вместо for и if используется только while. Плюс внутри цикла находится только повторяющаяся часть, а действие, один раз выполняющееся в конце цикла, находится там, где ему и положено быть - после цикла.
Таким образом, введение в язык и повседневную практику break убедительно обосновать Вы "не можете. Так и запишем." (С) Вы же :-)
Думаю, что спорить больше не о чем - все аргументы на лицо, каждый может оставаться при своём мнении, лучше не будем мешать нашим уважаемым функциональщикам "нецивилизованными императивными разборками" :-)
№ 3256 06-10-2007 06:56 | |
Ответ на »сообщение 3237« (Jack Of Shadows)
___________________________
Хаскелистам и лисперам глубоко фиолетово как у вас там отношения с break складываются.
Другой вопрос если дискуссия идет в русле сравнения этих самых for while break с аналогичным функциональным кодом, map fold и рекурсией. Вот тут можно и поговорить :)
Кстати, Jack, давно хотел Вас спросить (вроде бы ещё по этому поводу не высказывались?), как Вы, как функциональщик, к yield return относитесь?
Это движение в сторону ФП?
По-моему, несмотря на то, что штука, конечно, удобная, но это разрушение самого понятия функции, ввод ещё одного состояния ("замороженного" состояния функции) и отход далеко от функциональной парадигмы. А что Вы скажете?
№ 3255 06-10-2007 06:53 | |
Ответ на »сообщение 3254« (Илья Ермаков)
___________________________
Я специально не на Обероне, а то начнутся придирки к мелочам навроде "а WHILE большими буквами некрасиво...".
Вы специально на языке с самым запутанным синтаксисом, чтобы было понятнее? Ну-ну...
Итого Ваш вариант на Python:
def hasitem(list, value):
i = 0
while (i < len(list)) and (list[i] != value):
i = i + 1
return i != len(list)
Мой вариант на Python:
def hasitem(list, value):
for item in list:
if item == value:
return True
return False
В котором месте Ваш вариант понятнее моего?
Ответ на »сообщение 3253« (Илья Ермаков)
___________________________
Учите матчасть.
С матчастью у меня все в порядке. А применять цикл for для эмуляции while я не собираюсь - предпочитаю более понятные и очевидные конструкции.
№ 3254 06-10-2007 05:27 | |
Или Вас ипугал сишный синтаксис? Я специально не на Обероне, а то начнутся придирки к мелочам навроде "а WHILE большими буквами некрасиво...".
for(List::iterator i = list.begin(); i != list.end() && *i != value; ++i);
return i != list.end();
в С это полностью эквивалентно следующему:
List::iterator i = list.begin();
while ( i != list.end() and *i != value )
return i != list.end();
Так яснее? :-)
№ 3253 06-10-2007 04:18 | |
Ответ на »сообщение 3248« (panda)
___________________________
Ответ на »сообщение 3236« (Илья Ермаков)
___________________________
Т.е. циклом while вы пользоваться не умеете. Только рассуждаете о том, какой он правильный. Так и запишем.
Уважаемый господин, Вам было показано решение Вашего примера с использованием цикла без применения break (для явной синтаксической спецификации инициализации, условия и изменения использовав С-шный for). Полностью соответствующее правилам структурного программирования. Вы даже не удосужились (или не сумели) понять, как этот цикл работает. »сообщение 3236« - Вам это было объяснено.
Учите матчасть.
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|