Функциональное программирование |
Функциональное программирование всегда привлекало меня в противопоставлении к императивному.
Я очень часто обсуждаю различные аспекты функционального программирования на различных ветках на Базарной площади.
Но хотелось бы собрать всех заинтересованный этой темой в одной ветке.
Я думаю что настало время открыть такую тему. И вот почему.
Исторически функциональное программирование появилось практически вместе с императивным.
Вторым языком после фортрана был лисп.
Но увы, функциональное программирование надолго было уделом исследовательских институтов или специализированных приложений (Искусственный Интеллект)
Конечно не надо считать весь мир дураками из за того что развитие пошло по пути языков Алгол семейства.
Для этого были вполне обьективные причины. Функциональные языки слишком близки к человеку и слишком далеки от машины.
Они сьедают в десятки раз больше рессурсов чем императивные языки.
Вспомните претензии, предявляемые к java - первому императивному языку с виртуальной машиной и сборщиком мусора, толкаемому большими корпорациями в mainstream.
Жутко тормозит, и жрет всю память какая есть. А ведь функциональные языки (далее ФЯ) все без иключения имеют сборщик мусора, виртуальную машину.
Многие из них (семейство лисп) еще и динамические, что только усугубляет положение.
Вполне естественно что появившись более полусотни лет назад они надолго опередилли свое время.
Для широкого распространения ФЯ нужны гигабайты дешевой памяти и гигагерцы дешевых процессоров.
Прошло более 50 лет, прежде чем такие требования к железу стали реальностью.
Это время наступило. СЕЙЧАС.
Добро пожаловать в новую эру программирования.
Jack Of Shadows
Всего в теме 5502 сообщения
Добавить свое сообщение
Отслеживать это обсуждение
- Средства разработки. Языки программирования.
- Delphi 4 or Delphi 5
- Что приобрести в качестве средства разработки?
- Delphi6
- Delphi vs PowerBuilder
- Сравнение компиляторов
- Вот и вышла Delphi 7... Вы рады?
№ 1922 21-02-2007 19:12 | |
Ответ на »сообщение 1920« (Илья Ермаков)
___________________________
Просто складывается такое впечатление после долгих наблюдений за этой веткой и изучения источников по Хацкелу.
Илья, вам уже давно пора не "источники по хаскелю" изучать, а сам хаскель.
Скачаивайте GHC, читайте вот http://en.wikibooks.org/wiki/Programming:Haskell и пишите программы.
Через пару недель возвращайтесь :))
№ 1921 21-02-2007 19:07 | |
Ответ на »сообщение 1920« (Илья Ермаков)
___________________________
Вы о чем ? О том что иногда (далеко не всегда, а когда речь идет о миллиарде итераций)
явное указание типов (одна строчка!!!) является ТЯЖЕЛОЙ (!!!) НЕПЕРЕНОСИМОЙ (!!!) и НЕТРИВИАЛЬНОЙ (!!!) работой ?
Или вы что то другое имеете в виду ? :)))
№ 1920 21-02-2007 17:50 | |
Ответ на »сообщение 1918« (Jack Of Shadows)
___________________________
По поводу последнего десятка постов...
Что же в итоге получается, На "ФП писать очень просто". Но... Как только мы захотим завернуть нечто такое "очень простое", мы тут же упремся в то, что совершенно неизвестно, как это будет выполняться. С абстрактной точки зрения и превосходно - кто ж против-то забыть о деталях реализациях? А с практической точки зрения выходит, что множество кодов на ФП могут иметь совершенно недетерминированное время выполнения - все упирается в итоге в конкретную реализацию и ее способности к оптимизации. При этом если в ИЯ разбор по времени может быть 10-50%, то здесь, как видим, разы, а то и порядки, притом не только по времени, но и по памяти.
Т.е. исходный код на ФП недетерминирован по ресурсоемкости. Значит - во многих случаях непереносим без переделки? Но при этом явно повлиять на метод выполнения в ФП мы не можем, приходится все подгонять "нюхом"?
Что же получается - за что боролись, на то и напоролись? Избыточная абстрагированность убивает детерминированность и переносимость кода?
Как же тогда быть с утверждением, что в "ФП нет паттернов"? А разве нюансы, "как следует писать, а как не следует, чтобы компилятор, может быть, это реализовал приемлемо" не являются чистой воды паттернами? Все это мне подозрительно начинает напоминать С++ и Страуструпа с его бесконечными "а вот так не делайте" и "так тоже не надо".
P.S. Я, естественно, могу ошибаться и сильно ошибаться. Просто складывается такое впечатление после долгих наблюдений за этой веткой и изучения источников по Хацкелу.
№ 1919 21-02-2007 17:03 | |
Наивный вопрос.
Это так задумано, что в 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)))
№ 1918 21-02-2007 15:31 | |
Только что меня такой баг укусил, у меня аж глаза на лоб полезли. :)))
В Дельфи функция возвращает значение переменной Result (ну или переменной с названием функции, кому как нравится)
При чем если забыть дать значение, то никакой ошибки.
В других языках либо требуется использовать return (компилятор даст ошибку если забудещь) либо значение последнего выражения становится возвращаемым значением функции (это в ФЯ)
Последние дни я плотно работал на лиспе, и привык к тому что функция возвращает последнее значение.
Вчера пришлось кое что делать на дельфях, написал функцию, про переменную Result забыл.
Компилятор ничего не сказал.
Хорошо у меня тесты (DUnit) а то ведь так бы и пошло в продакшн :))
№ 1917 21-02-2007 13:37 | |
Ответ на »сообщение 1916« (Jack Of Shadows)
___________________________
Кстати, да, тормозило потому, что тип счётчика n был Integer вместо Int. Миллиард вычитаний в арифметике больших чисел - весьма заметно...
А вот тип элементов списка значения не имеет: что Int, что Integer, или Float, Double, Bool или даже Complex (как Complex Float, так и Complex Double) - всегда 6+-1 сек.
№ 1916 21-02-2007 12:59 | |
Ответ на »сообщение 1914« (Geniepro)
___________________________
Да, проставил типы - и время упало аж до 5 секунд!
Преобразования типов - операция дорогостоящая.
И если где то в программе ее приходится делать многократно (а в данном случае аж миллиард раз), то лучше избавить компилятор от этой работы, просто дав ему эту информацию.
№ 1915 21-02-2007 12:48 | |
Ответ на »сообщение 1913« (pepper)
___________________________
Попробуйте вот так:
import Time
main = do
print ((take 1000000001 $ repeat 0)!!1000000000)
У меня отрабатывает за 17 секунд.
А тормозит потому что перебираете миддиард элементов списка по одному. Задача не из быстрых :)
Например Дельфи не смог - выдал ошибку
List Capacity is out of bounds
№ 1914 21-02-2007 12:33 | |
Ответ на »сообщение 1913« (pepper)
___________________________
А почему тормозит (я не смог дождаться, пока программа закончит выполняться)?
Ну, что тут скажешь? Вопрос к разработчикам GHC...
В таких простеньких тестах GHC 6.6 меня тоже расстраивает - GHC 6.5 выдавал в полтора раза более быстрый код.
Видимо, переделки транслятора под поддержку SMP и оптимизация библиотеки ByteString как-то негативно сказались на быстродействии таких тестов...
На моём Селероне 1700 эта программа выполнялась 140 сек, а когда я указал тип Int (32-bit integers) - 32 сек. По умолчанию использовался тип Integer; видимо создание и выборка этих больших чисел намного медленнее, чем Int.
Кстати, если немного оптимизировать текст программы:
import Time
test_list :: [Int]
test_list = 0 : test_list
index :: [Int] -> Int -> Int
index (x:xs) 0 = x
index (x:xs) n = index xs (n-1)
main = do t <- getClockTime
print t
print (index test_list 1000000000)
t <- getClockTime
print t т.е. избавиться от принципиально ленивых функций head и tail (их, видимо, нельзя оптимизировать, по-крайней мере тут), то время выполнения уменьшается с 32 сек до 6 сек! В пять раз...
А вот с типом Integer всего лишь со 140 сек до 123 сек...
В-общем, делаем выводы: без особой нужды большими числами лучше не пользоваться, как и встроенными ленивыми функциями...
ЗЫ. А вот что меня удивило, аналогичный код на Clean, который традиционно считается создающим более быстрые программы, чем GHC, выполнялся в два раза медленнее - 13.7 сек...
module inflist
import StdInt
test_list = [0 : test_list]
index :: [Int] Int -> Int
index [x:xs] 0 = x
index [x:xs] n = index xs (n-1)
Start = index test_list 1000000000
№ 1913 21-02-2007 11:06 | |
Ответ на »сообщение 1912« (pepper)
___________________________
Поставил -O2. Та же фигня. Компилятор скачивал вчера. Может там еще чего-то покрутить надо?
Разобрался. Среда не перекомпилировала объектники после изменений опций. Сейчас памяти не жрет :) А почему тормозит (я не смог дождаться, пока программа закончит выполняться)?
Добавить свое сообщение
Отслеживать это обсуждение
Дополнительная навигация: |
|