Функциональное программирование |
Функциональное программирование всегда привлекало меня в противопоставлении к императивному.
Я очень часто обсуждаю различные аспекты функционального программирования на различных ветках на Базарной площади.
Но хотелось бы собрать всех заинтересованный этой темой в одной ветке.
Я думаю что настало время открыть такую тему. И вот почему.
Исторически функциональное программирование появилось практически вместе с императивным.
Вторым языком после фортрана был лисп.
Но увы, функциональное программирование надолго было уделом исследовательских институтов или специализированных приложений (Искусственный Интеллект)
Конечно не надо считать весь мир дураками из за того что развитие пошло по пути языков Алгол семейства.
Для этого были вполне обьективные причины. Функциональные языки слишком близки к человеку и слишком далеки от машины.
Они сьедают в десятки раз больше рессурсов чем императивные языки.
Вспомните претензии, предявляемые к java - первому императивному языку с виртуальной машиной и сборщиком мусора, толкаемому большими корпорациями в mainstream.
Жутко тормозит, и жрет всю память какая есть. А ведь функциональные языки (далее ФЯ) все без иключения имеют сборщик мусора, виртуальную машину.
Многие из них (семейство лисп) еще и динамические, что только усугубляет положение.
Вполне естественно что появившись более полусотни лет назад они надолго опередилли свое время.
Для широкого распространения ФЯ нужны гигабайты дешевой памяти и гигагерцы дешевых процессоров.
Прошло более 50 лет, прежде чем такие требования к железу стали реальностью.
Это время наступило. СЕЙЧАС.
Добро пожаловать в новую эру программирования.
Jack Of Shadows
Всего в теме 5502 сообщения
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Сравнение компиляторов
- Вот и вышла Delphi 7... Вы рады?
№ 1932 22-02-2007 02:13 | |
Ответ на »сообщение 1931« (AVC)
___________________________
(#<struct:promise> . #<struct:promise>)
У вас че то не то работает :))
Серьезно, там самый обычный вывод результата именно как вы и хотели.
Если хотите выходите на аську как время будет.
№ 1931 22-02-2007 02:07 | |
Ответ на »сообщение 1927« (Geniepro)
___________________________
>>>Вы, наверное, сгенерировали exe-файл и запустили его?
Нет, я пользуюсь интерпретатором.
Как таковой вывод есть:
> (map (lambda (x) (* x x)) (list 1 2 3 4))
(#<struct:promise> . #<struct:promise>)
просто это не то, что я ожидал увидеть (в соответствии с SICP).
Это ни в коем случае не критическое замечание (мне DrScheme нравится), а просто любопытство новичка. :)
№ 1930 22-02-2007 02:04 | |
>>>Аналитически формула верна, но практически
>>>неприемлема...
---
>>>"Оптимизация по полной" - это "вычисление программы
>>>в compile-time"?
---
Позвольте маленький комментарий к последней серии. Как ни странно, но кажется, что мои вопросы по "нестандартным вычислениям Фибоначчи" и последняя серия на тему оптимизации касаются одной важной темы - проблемы взаимоотношений "чистой" математики и прикладной математики (в смысле "технической" математики). По поводу 1 проблемы. Конечно, функция, вычисляющая F(n) через "идею" золотого сечения верна аналитически. Очень даже верна! Доказательство приводить не будем - слишком мало места :))). Но при этом с точки зрения практических вычислений абсолютно не состоятельна. Мой знакомый математик потому и математик ("чистый", не "прикладной"), что ему совсем не интересны такие "прикладные мелочи", как "машинный эпсилон"! Он получил на бумаге точную формулу и доказал ее верность. И ему этого достаточно. А в "машинной математике" эта формула оказалась совершенно бесполезной. Можно сказать, "почти неверной" :))).
Вторая тема. Проблема оптимизации. Что значит "полная оптимизация"? Это значит, что компилятор должен на этапе компиляции полностью понять нетривиальные свойства того кода, который вычисляет некоторую функцию. Или, другими словами, "понять" семантику того, что делает написанная программа. Например, понять, что большой список или миллиард итераций - это все "фикция", "подстава" со стороны программиста. Вместо всей этой белиберды надо просто взять и вывести нуль! С точки зрения "машинной математики" почему бы и нет? Почему компилятор не может полностью разобраться в том, что делает код, который он компилирует? И принять соответствующие решения по его улучшению. А вот для "чистого" математика здесь нет никакой проблемы. В том смысле, что "полная оптимизация" в принципе не возможна. Нигде и ни при каких условиях. Потому что есть теорема Райса-Успенского. А она гласит: Проблема определения любого нетривиального свойства алгоритма относится к классу алгоритмически неразрешимых проблем! Нетривиальное свойство - это такое свойство функции, которое у одних функций есть, а у других - нет. Практически это означает: Ни один самый-самый умный компилятор никогда не сможет полностью понять, что это мы "замутили" в своей умной программе. Теорема РУ не "позволит". Конечно, какие-то очевидные свойства он "разгадает". Но не все. И не полностью. А значит будет "крутить" какой-нибудь не очень "умный" цикл, который мы ему специально "подсунули", вместо того, чтобы просто нуль вывести.
Вот такие непростые отношения между "чистой" и "нечистой" математикой складываются :)
№ 1929 22-02-2007 01:06 | |
Ответ на »сообщение 1925« (pepper)
___________________________
Аналогичный императивный код примерно такой:
Вообще-то этот код далеко не аналогичен. Алгоритм-то в корне другой...
Современными сишными компиляторами этот цикл выкидывается.
Почему-то компилятор C# этот цикл оставляет, а ведь он считается весьма неплохим компилятором...
В свете всего сказанного в отношении возможностей оптимизации у функциональных языков, не очень понятно, что GHC мешает сделать оптимизацию по полной.
"Оптимизация по полной" - это "вычисление программы в compile-time"? :о))
№ 1928 22-02-2007 00:59 | |
Ответ на »сообщение 1920« (Илья Ермаков)
___________________________
Т.е. исходный код на ФП недетерминирован по ресурсоемкости.
Это свойство не именно функциональных языков, а ленивых (с нестрогой семантикой), каковым является ФЯ Хаскелл, например.
Возьмите Эрланг. Это чистый ФЯ со строгой семантикой и в нём можно весьма точно предсказывать поведение программы - soft real time. С точностью до десятков микросекунд, если я не ошибаюсь. Во всяком случае, та же Ява такой детерменированности не обеспечивает...
Значит - во многих случаях непереносим без переделки?
Действительно, причём здесь непереносимость? Код, сгенерированный разными трансляторами, может работать разное время, потреблять разное количество памяти - но точно так же и с другими, вполне даже императивными языками...
№ 1927 22-02-2007 00:53 | |
Ответ на »сообщение 1919« (AVC)
___________________________
Это так задумано, что в DrScheme рядовой пример из SICP
(map (lambda (x) (* x x)) (list 1 2 3 4))
не печатает желаемый список (1 4 9 16)?
Приходится явно использовать display:
(display (map (lambda (x) (* x x)) (list 1 2 3 4)))
Вы, наверное, сгенерировали exe-файл и запустили его?
Да, в этом случае, похоже, нужно явно указывать вывод результатов на печать...
Что, впрочем, и логично - Вы ведь в своих программах явно указываете, что Вам нужно распечатать, а что - нет, не так ли?
№ 1926 21-02-2007 23:42 | |
Ответ на »сообщение 1920« (Илья Ермаков)
___________________________
По поводу последнего десятка постов...
Что же в итоге получается, На "ФП писать очень просто". Но... Как только мы захотим завернуть нечто такое "очень простое", мы тут же упремся в то, что совершенно неизвестно, как это будет выполняться.
Не упремся. Не каждый день приходится иметь дело со списками в миллиард элементов.
Т.е. исходный код на ФП недетерминирован по ресурсоемкости.
Да. Как и код любого языка с GC (того же оберона, раз уж ты его поклонник). Исключения лишь подтверждают правило.
Значит - во многих случаях непереносим без переделки?
В смысле не переносим без переделки?
Но при этом явно повлиять на метод выполнения в ФП мы не можем, приходится все подгонять "нюхом"?
Представлять как будет вычисляться та или иная задача надо на любом языке. Есть какие-нибудь конкретные претензии к недетерминированности вычислений у хаскеля? Применительно к рассмотренному примеру, если программист пишет "бесконечный ленивый список" с последующим доступом к миллиардному элементу, то он вполне может ожидать, что программа съест очень много памяти. Поэтому программист не будет так писать :) Вполне возможно, что при попытке написать по-другому окажется, что получившийся код уже не такой простой и понятный, но никто и не обещал, что ФП будет панацеей и решением всех проблем :) Просто еще один компромисс.
От "подгонки" (в случае необходимости) никакой язык не избавляет. Про то, что "подгонка" наиболее эффективна не за счет кручения опций оптимизации, а за счет усовершенствования алгоритма - уже сто раз говорили. Так что каких-то фатальных недостатков именно у функциональных языков я в этом вопросе не усматриваю.
№ 1925 21-02-2007 23:11 | |
Ответ на »сообщение 1915« (Jack Of Shadows)
___________________________
А тормозит потому что перебираете миддиард элементов списка по одному. Задача не из быстрых :)
На самом деле задача - напечатать 0. Список - лишь абстракция (учитывая встроенность списков не вижу здесь каких-то ограничений для компилятора). Аналогичный императивный код примерно такой:
int n = 1000000000;
while (true)
Современными сишными компиляторами этот цикл выкидывается. В свете всего сказанного в отношении возможностей оптимизации у функциональных языков, не очень понятно, что GHC мешает сделать оптимизацию по полной.
№ 1924 21-02-2007 23:11 | |
Ответ на »сообщение 1918« (Jack Of Shadows)
___________________________
В Дельфи функция возвращает значение переменной Result (ну или переменной с названием функции, кому как нравится)
При чем если забыть дать значение, то никакой ошибки.
Совем недавно обсуждали в другой теме. Зависит от типа. Будет либо Warning, либо ничего (для String, например).
№ 1923 21-02-2007 19:25 | |
Ответ на »сообщение 1919« (AVC)
___________________________
Че то вы не то сказали.
Прекрасно печатает. Причем как из REPL так и из исходника.
Вы че там делаете ?
Для проверки привожу последовательность действий.
1. набираете в REPL - нажимаете Enter - тут же получаете ответ.
Второй вариант.
Набираете в окне текстового файла, нажимаете кнопку Run - тут же получаете ответ в окне REPL
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|