Функциональное программирование |
Функциональное программирование всегда привлекало меня в противопоставлении к императивному.
Я очень часто обсуждаю различные аспекты функционального программирования на различных ветках на Базарной площади.
Но хотелось бы собрать всех заинтересованный этой темой в одной ветке.
Я думаю что настало время открыть такую тему. И вот почему.
Исторически функциональное программирование появилось практически вместе с императивным.
Вторым языком после фортрана был лисп.
Но увы, функциональное программирование надолго было уделом исследовательских институтов или специализированных приложений (Искусственный Интеллект)
Конечно не надо считать весь мир дураками из за того что развитие пошло по пути языков Алгол семейства.
Для этого были вполне обьективные причины. Функциональные языки слишком близки к человеку и слишком далеки от машины.
Они сьедают в десятки раз больше рессурсов чем императивные языки.
Вспомните претензии, предявляемые к java - первому императивному языку с виртуальной машиной и сборщиком мусора, толкаемому большими корпорациями в mainstream.
Жутко тормозит, и жрет всю память какая есть. А ведь функциональные языки (далее ФЯ) все без иключения имеют сборщик мусора, виртуальную машину.
Многие из них (семейство лисп) еще и динамические, что только усугубляет положение.
Вполне естественно что появившись более полусотни лет назад они надолго опередилли свое время.
Для широкого распространения ФЯ нужны гигабайты дешевой памяти и гигагерцы дешевых процессоров.
Прошло более 50 лет, прежде чем такие требования к железу стали реальностью.
Это время наступило. СЕЙЧАС.
Добро пожаловать в новую эру программирования.
Jack Of Shadows
Всего в теме 5502 сообщения
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Сравнение компиляторов
- Вот и вышла Delphi 7... Вы рады?
№ 282 20-06-2006 13:13 | |
Ответ на »сообщение 277« (hugi)
___________________________
Кто-то из современных великих сказал, что постепенно все программисты приходят к тому, что начинают в своих программах эмулировать лисп-программы... ;)
Скажите, а в вашей интерпретации, элементы ДЕЙСТВИТЕЛЬНО полиморфны или только в рамках понятий полиморфности объектов Явы? Я имею в виду воплощение прямого "постулата" Лиспа о неразличимости формы записей списка элементов и вызова функции? (Это важно, это - не просто каприз на счёт синтаксиса...)
И что для этого надо сделать В РАМКАХ Явы?
И как это будет выглядеть в смысле наглядности и "затратности" по записи кода таких операций для кода клиента?
Я это к чему спрашиваю? К тому, что накропать набор основных функций работы с множествами можно и на ассемблере. Уж куда более императивщина?... ;)
Есть ещё один маленький вопросик. Всё-таки вы вынуждены акцентировать внимание пользователя вашей реализации на раздельности понятий объектов списка и элемента списка. Заметьте, я здесь даже не упоминаю лисповское понятие атома.
В вашем примере мне было бы интересно посмотреть даже не на код заполнения списка, а на код, например:
- использующий элементы списка;
- получающий доступ к элементам списка;
- пытающийся получить хвост списка;
- оперирующий списком, как целым.
Пожалуйста, используя ваш класс, приведите полный пример для иллюстрации использования вашего класса "в деле", в которм были бы показаны перечисленные выше случаи...
№ 281 20-06-2006 13:12 | |
Ответ на »сообщение 279« (Jack Of Shadows)
___________________________
Простите, но в лиспе есть циклы. И в ocaml есть циклы. Так что все что делается рекурсией может быть сделано и циклом.
Лисп в такой же степени функциональный, в какой С -- модульный. Это не чистый ФЯ, и, на мой взгляд, нет смысла всё время ставить его в пример. В чистых ФЯ циклов НЕТ, только рекурсия.
Почему программисты у которых есть выбор (цикл или рекурсия в лиспе) предпочитают рекурсию ? Почему в лиспе рекурсия - широко используемый прием (хотя есть полноценные циклы) ?
Я писал об этом в предыдущем сообщении. Это идеология языка. Акценты. Общепринятая техника. По этой же причине программисты на ИЯ чаще используют циклы. Повторюсь, не из-за технических проблем, как Вы пытались представить, а по идеологическим причинам и вследствие общераспространённой практики.
К тому же рекурсия характеризуется меньшей прозрачностью, чем цикл. Все эти раскручивания стека, в то время, когда в цикле всё лежит на поверхности.
№ 280 20-06-2006 12:57 | |
Ответ на »сообщение 279« (Jack Of Shadows)
___________________________
"невозможно" относилось не к рекурсии, а к техническим трудностям, которые возникают при ее применении в ИЯ.
Я прекрасно осознаю, что Вы имели в виду. И, если Вы заметили, в своём »сообщение 274« я приводил цитаты, относящиеся к использованию рекурсии при обработке списков. Ну да ладно.
Далее. Вы утверждали, что в ИЯ невозможна обработка списков методом первый-последние. Panda привёл пример-опровержение, я привёл пример-опровержение.
Вы всё ещё намерены утверждать, что при рекурсии больших списков в ИЯ, программа просто сдохнет из за элементарного пепеполнения стека, или признаете, что этого не произойдёт?
При применении рекурсии в ИЯ не возникает никаких технических трудностей, это скорее вопрос мировоззрения. В ФЯ акценты смещены в сторону рекурсии (при этом не используются временные переменные, сотояние которых пришлось бы изменять). В ИЯ то, что можно делать циклом, нет смысла делать с помощью рекурсии, т.к. Вы правильно заметили, в ИЯ циклы более естественны, но это связано с идеологией ИЯ, а не с техническими трудностями.
№ 279 20-06-2006 12:30 | |
Ответ на »сообщение 274« (hugi)
___________________________
что делает применение рекурсии в лучшем случае трудным, в худшем (обработка больших списков) невозможным.
Ах вот вы где нашли слово невозможно :)))
Поразительно. В этом же предложении я говорю, что рекурсия возможна ("в лучшем случае трудным") но вы в упор этого не видите, после чего выдираете слово "невозможно" из контекста, и давай меня пинать ногами.
Господа защитники рекурсии в ИЯ. Если вы внимательно прочитаете все предложение, не выдирая никаких слов, то поймете, что "невозможно" относилось не к рекурсии, а к техническим трудностям, которые возникают при ее применении в ИЯ. Так например при рекурсии больших списков в ИЯ, программа просто сдохнет из за элементарного пепеполнения стека. Ну нет в ИЯ tail call elimination.
Надеюсь с "невозможно" разобрались ?
Но, заметьте, пока Вас никто не попросил привести на ФЯ пример перебора элементов списка без рекурсии (что является АБСОЛЮТНО ЕСТЕСТВЕННЫМ для ИЯ и В ПРИНЦИПЕ НЕВОЗМОЖНЫМ для ФЯ).
Опять "невозможным". Простите, но в лиспе есть циклы. И в ocaml есть циклы. Так что все что делается рекурсией может быть сделано и циклом.
Вы мне вот что скажите. Почему программисты у которых есть выбор (цикл или рекурсия в лиспе) предпочитают рекурсию ? Почему в лиспе рекурсия - широко используемый прием (хотя есть полноценные циклы) ?
Почему в ИЯ, не смотря на то что вроде бы тоже есть выбор (цикл или рекурсия) 99% случаев выбор падает на цикл ?
В чем дело ? Вот вы привели код. Ах как легко! Вот panda привел код. Да черт возьми, я сам могу писать рекурсию на дельфи. Но разве вы это делаете на практике ? Разве я это делаю на практике ? Не для того чтобы выставить кого то неправым, не для того чтобы решить какую то специфическую задачу, а просто как обычный инструмент работы с циклическими алгоритмами.
Как видите вы и сами не верите в сделанный вами же самими код. Потому что пишете таким образом только для бессмысленного доказательства теоретической возможности "и мы так могем".
Это все равно что написать на си ОО код (есть библиотеки), для того чтобы доказать что си является ОО языком. Но разве вы примете такое доказательство ? Ведь оно не подтверждается практикой.
Не достаточно чтобы язык имел возможность. Нужно еще чтобы эта возможность была ДОСТАТОЧНО УДОБНОЙ.
Поэтому си не является обьекто-ориентированным языком, а ИЯ не является "рекурсивно-ориентированным".
№ 278 20-06-2006 12:11 | |
Ответ на »сообщение 268« (panda)
___________________________
Например, есть ли Lisp, который умеет встраиваться в Microsoft Script Control (как ActivePython)?
Несколько.
LSharp - http://lsharp.org/ - работает на dotnet. Встраивается как как dll
DotLisp http://dotlisp.sourceforge.net/dotlisp.htm - работает на dotnet. Встраивается как как dll
Embedded Common Lisp - http://ecls.sourceforge.net/ - Встравиается во что угодно, начиная с Си, и заканчивая VisualBasic.
lispworks.com (коммерческий) - может работать как activex server.
Возможно если вы посмотрите на common-lisp.net В разделе implementations, то найдете еще.
Во всяком случае есть еще лиспы, работающие на java? то есть тоже могту встраиваться, но в java.
№ 277 20-06-2006 10:31 | |
Ответ на »сообщение 259« (Jack Of Shadows)
___________________________
Вам уже приводили пример обработки списка по методу первый-остальные, но он Вас почему-то не удовлетворил. Может этот Вы оцените более высоко (следуя Вашему примеру выложил на paste.lisp.org):
http://paste.lisp.org/display/21480
Delphi, к сожалению, под рукой не оказалось, поэтому писал на Java. Благодаря этому более естественным выглядит возврат значения из функции (с помощью return, а не псевдопеременной Result).
Сделаю некоторые комментарии.
Базисные операции объявлены как статические методы в классе FP. В этом же классе описан внутренний класс FPListItem, представляющий собой список (более строго -- элемент списка). Класс имеет два аттрибута: value типа Object, чтобы можно было запихивать всё, что угодно (в том числе и список), и next, указывающее на следующий элемент списка. Доступ к аттрибутам осуществляется с помощью операций setXXX/getXXX, но это не существенный момент. Существенным моментом является то, что реализация списка, и все операции, с помощью которых производится манипуляция значениями аттрибутов, скрыты от клиентов. Благодаря этому манипулировать списком можно только с помощью базисных операций, объявленных в том же классе FP. Всего этих операций три: join() -- конструктор списков (создаёт список из двух элементов), head() -- получить первый элемент, tail() -- получить последние элементы, причём join перегружена, чтобы наглядно продемонстрировать все возможные варианты комбинации параметров. Как видите, я подходу, принятому в ФЯ.
В классе FPLib статически определена операция append() -- слияние списков (тоже перегружена для пущей наглядности). Эта операция использует в своей работе исключительно базисные операции импортируемые из класса FP, не имея доступа к реализации элемента списка.
В классе Test производится тестирование операций над списками. Описывается операция sum(), подсчитывающая сумму элементов списка. В методе main() осуществляется чтение с консоли набора целых чисел (в цикле while), вводимых построчно, пока не будет получена пустая строка. В этом же цикле по мере ввода с помощью операции append() создаётся список. Можно было бы, конечно, и при вводе использовать рекурсию, но это, на мой взгляд, совсем уж извращение.
Сумма, как ни странно, подсчитывается правильно.
Таким образом, на ИЯ (Java) полностью (ну или почти) удалось симитировать функциональный стиль работы со списками. Причём получилось довольно читабельно (на мой взгляд, не намного более громоздко, чем в ФЯ). Везде используется рекурсия (кроме метода main, где осуществляется ввод). К тому же ВСЕ функции -- чистые (опять же, кроме main).
Вот, пожалуй, и всё. Будут вопросы, спрашивайте. Обязательно отвечу.
Да, кстати, копирования данных при вызове функции tail() не происходит.
№ 276 20-06-2006 09:07 | |
Ответ на »сообщение 264« (Jack Of Shadows)
___________________________
Причина любого выбора в пользу той или иной техники заключается в ее удобстве, легкости и практичности по сравнению с остальными вариантами. В ИЯ рекурсия неудобна, трудна и непрактична по сравнению с вариантом решения при помощи итераций (циклов).
Частично согласен. Но в данном случае среда налагает на программиста ограничения. Если Вы пишете на ФЯ, то просто не можете использовать цикл (речь о чистых ФЯ). Если Вы пишете на ИЯ, то вы можете использовать как цикл, так и рекурсию. Причём в некоторых случаях удобно применять одно, а в иных -- другое. Т.е. в ИЯ у программиста больший выбор тактик решения задачи. Теперь по поводу списка. Список в ФЯ является фундаментальной структурой, вокруг которой всё вращается. Это накладывает ограничения на состав языка и на технику работы с данными в нём (хотя, с другой стороны, использование именно списка было призвано обеспечить отсутствие побочных эффектов). В ИЯ список -- всего лишь один из многих типов данных, с которыми у него полное равноправие. Т.е. в ФЯ всё заточено на работу со списками, а ИЯ предлагают универсальный подход ко всем типам данных. Поэтому обработка списков в ФЯ может выглядеть более компактно по сравнению с аналогичным (выполненным в духе ФЯ) решением в ИЯ.
№ 275 20-06-2006 08:45 | |
Ответ на »сообщение 265« (Jack Of Shadows)
___________________________
Ведь сторонники ФЯ приводят именно практичные, удобные примеры а не изворачиваются ради доказательства "и мы так могем"
Вы льстите сторонникам ФП. Приведённые Вами примеры лично мне были не очень понятны, да и другим тоже. Но, заметьте, пока Вас никто не попросил привести на ФЯ пример перебора элементов списка без рекурсии (что является АБСОЛЮТНО ЕСТЕСТВЕННЫМ для ИЯ и В ПРИНЦИПЕ НЕВОЗМОЖНЫМ для ФЯ).
А приведённый panda пример, на мой взгляд, был призван опровергнуть Ваше утверждение, что работа со списками в ИЯ по примеру (первый, последние) невозможна.
И получилось то всё, кстати, как в любом ФЯ, конечно, с поправкой на синтаксис Delphi (отсутствие образцов, типичных для ФЯ, использование присваивания псевдопеременной Result, и т.д). Семантических же отличий абсолютно никаких.
№ 274 20-06-2006 08:31 | |
Ответ на »сообщение 259« (Jack Of Shadows)
___________________________
Jack, вот что Вы пишите в »сообщение 248«:
ОК, но почему бы не работать с first и rest в ИЯ ? Разве нельзя вернуть список в которм убран первый элемент ?
Физически можно. Практически нереально.
Функцию first реализовать в ИЯ легко. А вот rest (остальные) - трудно. Для этого придется каждый раз создавать новый список без первого элемента и передавать его дальше.
Представьет себе обработку списка из миллиона записей. Любой компьютер сдохнет! Никакой памяти не хватит!
и далее:
Попытки применять рекурсию в ИЯ утыкаются в физические особенности конструкции ИЯ, что делает применение рекурсии в лучшем случае трудным, в худшем (обработка больших списков) невозможным.
Следует подчеркнуть последнее слово: "НЕВОЗМОЖНЫМ".
В »сообщение 255« вы продолжаете:
Это в отличии от ИЯ где пытаясь работать со списком рекурсивно, неизбежно придется разбирать список на части.
Чтобы этого избежать, приходится работать в цикле.
и ещё:
На элемент можно [вернуть указатель], а вот на часть списка, начиная с какого то элемента как на новый список (подсписок) нельзя.
Вам придется создавать этот подсписок заново.
А потом вдруг резко меняете позицию:
Мы говорим о том что легко/трудно а не о том что возможно/невозможно.
То есть, до этого было НЕВОЗМОЖНО, то после стало ТРУДНЫМ.
Либо Вы сами запутались, либо неточно выражаетесь, либо просто не хотите признать, что
panda своим примером опроверг Ваши утверждения. Разумеется, Вашим оппонетам наиболее вероятным покажется последний вариант, что не пойдёт на пользу дискуссии.
№ 273 20-06-2006 08:27 | |
Ответ на »сообщение 265« (Jack Of Shadows)
___________________________
Вот я и прошу, приведите практический пример использования рекурсии в дельфи, который в сравнении с решением через итерацию был бы более легок в написании, более удобен, более практичен.
Тогда будет что обсуждать.
1. Преобразование числа в строку
2. Быстрая сортировка
3. Вычислитель выражений
ИМНО, рекурсиврые реализации проще, хотя и не много короче.
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|