M>>Главная проблема императивщины в том, что она убирает любую декларативность из программирования и за деревьями не видно леса. ФП предлагает возможность описать задачу в терминах «что надо сделать», а не «как это сделать».
EP>Нет, не предлагает. Несмотря на лаконичный синтаксис, это всё равно описание "как это сделать". Например поменяв строчки в примере fac местами — получим stackoverflow.
Это все равно приближено описание «что сделать».
EP>Причём это "как" зачастую плохо отображается на современные железо. Лаконичный и "типа декларативный" fibs — тормоз
— именно потому что описывается "как", а не "что." И только потому что описывается "как" приходится знать о таких вещах "как" хвостовая рекурсия, чтобы понимать и иметь возможность переписать через дополнительный acc параметр, убивая изначальную "типа декларативность".
Еще один Шеридан с абстрактными заявлениями про скорость.
Здравствуйте, Mamut, Вы писали:
M>Это все равно приближено описание «что сделать».
Ровно через то, как это сделать. Вообще-то фибоначчи можно считать и совсем по-другому, например, экспоненцированием матрицы, что для больших n гораздо оптимальнее при эффективной реализации умножения. Но вряд ли сейчас существует среда, которая по описанию "что сделать", найдёт самый быстрый способ это сделать. Именно поэтому в любом существующем языке описывается именно "как сделать", пусть и с разной степенью детализации (в пределах догадливости компилятора) и разными допусками (например, с возможностью обрабатывать элементы контейнера в произвольном порядке).
M>Еще один Шеридан с абстрактными заявлениями про скорость.
Гм, а вот это уже переход на личности, причём третьих лиц. По существу, в чём возражения против того, что прямое отображение функциональных парадигм на современное железо часто приводит к неэффективному коду? И что с этим приходится бороться малоестественными приёмами типа переделки рекурсии в хвостовую?
Здравствуйте, Mamut, Вы писали:
M>>>Главная проблема императивщины в том, что она убирает любую декларативность из программирования и за деревьями не видно леса. ФП предлагает возможность описать задачу в терминах «что надо сделать», а не «как это сделать». EP>>Нет, не предлагает. Несмотря на лаконичный синтаксис, это всё равно описание "как это сделать". Например поменяв строчки в примере fac местами — получим stackoverflow. M>Это все равно приближено описание «что сделать».
Несмотря на то что по форме есть некоторые сходства с математическим декларативным описанием, это всё же описание "как это сделать"
EP>>Причём это "как" зачастую плохо отображается на современные железо. Лаконичный и "типа декларативный" fibs — тормоз
— именно потому что описывается "как", а не "что." И только потому что описывается "как" приходится знать о таких вещах "как" хвостовая рекурсия, чтобы понимать и иметь возможность переписать через дополнительный acc параметр, убивая изначальную "типа декларативность". M>Еще один Шеридан с абстрактными заявлениями про скорость.
"O(fib n) additions" вместо O(n) на ровном месте — это абстрактное заявление про скорость?
M>>Еще один Шеридан с абстрактными заявлениями про скорость.
EP>"O(fib n) additions" вместо O(n) на ровном месте — это абстрактное заявление про скорость?
Да. Извини, но это даже не хочется обсуждать, если ты этого не понимаешь.
M>>Еще один Шеридан с абстрактными заявлениями про скорость.
C>Гм, а вот это уже переход на личности, причём третьих лиц. По существу, в чём возражения против того, что прямое отображение функциональных парадигм на современное железо часто приводит к неэффективному коду?
Да. Неэффективный код может быть. Да, например у того же Erlang'а проблемы вообще с архитектурой современных машин, и Erlang VM — это, по сути, самостоятельная ОС, мало имеющая отношения к тому, что под ней.
И? Дальше что? Это все равно — теоретические изыски. На практике надо смотреть реальные задачи и доатсточно ли нам этой скорости.
C>И что с этим приходится бороться малоестественными приёмами типа переделки рекурсии в хвостовую?
Здравствуйте, Mamut, Вы писали:
M>Да. Неэффективный код может быть. Да, например у того же Erlang'а проблемы вообще с архитектурой современных машин, и Erlang VM — это, по сути, самостоятельная ОС, мало имеющая отношения к тому, что под ней.
Тут можно только ответить, что других архитектур и современных машин у меня для Вас пока нет
Кстати, возможно, что проблемы у него не столько с современными машинами, сколько с нашей физической реальностью. Чего именно ему не хватает в современных машинах, и как это можно было бы исправить, чтобы программы на Эрланге работали эффективно (не медленее, чем на существующем C++)? Не нарушая законы физики?
M>И? Дальше что? Это все равно — теоретические изыски. На практике надо смотреть реальные задачи и доатсточно ли нам этой скорости.
Конечно, всегда можно сказать, что того, что мы имеем, нам вполне достаточно, а то, чего мы не имеем, нам совершенно не нужно. Примерно так делала лисица в известной басне.
Однако, если мы с помощью примитивной императивщины имеем экспоненциально более быструю реализацию, чем с помощью функционального подхода, то возникает вопрос: ради чего мы должны отказаться от первой в пользу второго?
C>>И что с этим приходится бороться малоестественными приёмами типа переделки рекурсии в хвостовую? M>Что в этом малоестественного?
Это малоестественно в плане предлагаемой Вами математичности: естественное описание задачи, если мы хотим, чтобы она решалась быстро, оказывается похоронено под грудой костылей. Причём гораздо более сложной, чем в императивном случае. В данном случае можно предположить, что так приходится делать из-за того, что современные функциональные языки находятся в младенческом состоянии, вот-вот они научатся сами выявлять возможности переделки рекурсии в хвостовую, а ещё через чуть-чуть — понимать, как линейное вычисление можно переделать в логарифмическое, заодно сами же станут определять в каждом конкретном случае, какой вариант быстрее. Но именно это мы уже давно слышали от лисперов: функция стала полноправным членом программы, теперь компилятор может анализировать её исходный код, и уж с помощью компьютера он найдёт гораздо лучший способ перевести её в машинный код, чем человек. Но только воз и ныне там. Хорошо хоть научились хвостовую рекурсию переделывать в цикл (императивщина!), и теперь можно ему подсказывать, не выходя за рамки функционального подхода. Но помогает это не всегда.
Ещё один хороший пример — так любимый функциональщиками квиксорт. Что ему приходится вытворять с памятью из-за ограничения немодифицируемости существующих данных — это отдельная песня. Или можно вспомнить ленивость в хаскеле, с которой умеют бороться только положившие на это жизнь гуру.
Здравствуйте, BulatZiganshin, Вы писали:
I>>Странное мнение. Если начать осваивать программирование с процессора, то окажется, что никакого ФП и близко нет, всё насквозь мутабельное.
BZ>а если изучить как физически устроены процессоры то окажется что это чистое ФП, которое протянули через угольное ушко императивности.
Процессор весь насквозь мутабельный и императивный. Более того, процессор уже лет 20 или 30 невозможно описать аналитически. Даже кеш и тот не описывается аналитически.
Здравствуйте, Ikemefula, Вы писали:
I>Более того, процессор уже лет 20 или 30 невозможно описать аналитически. Даже кеш и тот не описывается аналитически.
А вот отсюда можно поподробнее? Что значит "описать аналитически" и почему нельзя? Вроде бы детерминированная фигня, моделируют её програмно.
Здравствуйте, dimgel, Вы писали:
I>>Более того, процессор уже лет 20 или 30 невозможно описать аналитически. Даже кеш и тот не описывается аналитически.
D>А вот отсюда можно поподробнее? Что значит "описать аналитически" и почему нельзя? Вроде бы детерминированная фигня, моделируют её программно.
Моделируют программно, но невозможно написать одну большую функцию сигнала от времени для каждой из ножек.
Здравствуйте, cures, Вы писали:
C>а ещё через чуть-чуть — понимать, как линейное вычисление можно переделать в логарифмическое, заодно сами же станут определять в каждом конкретном случае, какой вариант быстрее.
Кстати, императивное программирование принципиально не препятствует логарифмической оптимизации линейно-рекуррентного кода. То есть в этом аспекте не видно преимущества от использования ФП (по крайней мере в контексте современных ФП языков).
C>Ещё один хороший пример — так любимый функциональщиками квиксорт. Что ему приходится вытворять с памятью из-за ограничения немодифицируемости существующих данных — это отдельная песня.
Суть настоящего quicksort именно в перестановке элементов in-place, это даже упоминал Erik Meijer в одном из своих видео по Haskell. То есть настоящий quicksort на Haskell придётся реализовывать через императивный код на монадах. А тот пример который обычно называют quicksort — таковым не является.
Здравствуйте, Evgeny.Panasyuk, Вы писали:
EP>Суть настоящего quicksort именно в перестановке элементов in-place, это даже упоминал Erik Meijer в одном из своих видео по Haskell.
Это ещё Вирт в "Алгоритмах и структурах данных" упоминал, что-то типа "логично, что усовершенствованный вариант 'прямого обмена', как самого тормозного из трёх базовых алгоритмов, дал самый большой прирост производительности, но чтобы настолько..."
Здравствуйте, Evgeny.Panasyuk, Вы писали:
BZ>>fib 0 = 1 BZ>>fib 1 = 1 BZ>>fib n = fib(n-1) + fib(n-2)
EP>Эта наивная реализация requires O(fib n) additions В то время как в наивной итеративной версии будет линейное количество сложений.
Здравствуйте, BulatZiganshin, Вы писали:
EP>>>>Какой вариант тебе понятней? Императивное вычисление чисел Фибоначчи? EP>>Эта наивная реализация requires O(fib n) additions В то время как в наивной итеративной версии будет линейное количество сложений. BZ>мемоизация ненамного сложнее: BZ>fib 0 = 1 BZ>fib 1 = 1 BZ>fib n = fibs!!(n-1) + fibs!!(n-2) BZ>fibs = map fib [0..]
Всё равно до итеративной версии ещё далеко — у версии с мемоизацией линейная сложность по памяти, вместо положенной константой — и это всё ещё простейший пример.
И кстати, как видно нет тут никакой хвалёной декларативности/math-like. А по понятности на мой вкус хуже итеративной версии.
BZ>а теперь попробуй добавить мемоизацию в сишную функцию. только без глоб. переменных, будь ласка
Здравствуйте, cures, Вы писали:
EP>>Я кстати не помню чтобы компилятор вставлял loop — везде был явный счётчик и условный переход.
C>Это потому, что она если и была когда-то эффективней отдельных декремента и условного перехода, то очень давно, во времена 8086. Кстати, с декрементом такая же фигня по сравнению с обычным вычитанием. Их даже отменили в 64-битном режиме, чтобы освободить место для новых инструкций. C>Так что можете считать, что инструкции loop в ассемблере нет
Скажу по секрету — ее никогда не было по большому счету
Даже во времена 8086 ее мало кто использовал
M>>И? Дальше что? Это все равно — теоретические изыски. На практике надо смотреть реальные задачи и доатсточно ли нам этой скорости.
C>Конечно, всегда можно сказать, что того, что мы имеем, нам вполне достаточно, а то, чего мы не имеем, нам совершенно не нужно. Примерно так делала лисица в известной басне.
Демагогия
C>Однако, если мы с помощью примитивной императивщины имеем экспоненциально более быструю реализацию, чем с помощью функционального подхода, то возникает вопрос: ради чего мы должны отказаться от первой в пользу второго?
Выразительность, скорость разработки.
C>>>И что с этим приходится бороться малоестественными приёмами типа переделки рекурсии в хвостовую? M>>Что в этом малоестественного?
C>Это малоестественно в плане
демагогии и абстрактных заявлений про абстрактную скорость для абстрактных сферовакуумных задач, которую извини, но я скипнул.
На практике ничего неестественного в хвостовой рекурсии нет. И на практике в подавляющем количестве задач все упрется в базу/сеть/скорость записи на диск быстрее, чем оно упрется в проблемы со производительностью ФП
Смысл есть во многом. В функциональном программировании он тоже есть. Идея использования функций как объектов и манипулирования с ними совсем не так плоха. Что плохого, скажем, в передаче функции — фильтра в некую функцию поиска или же функции — подинтегрального выражения в функцию вычисления интеграла ?
И в иммутабельности ничего плохого нет. Меньше изменений — меньше риска сделать ошибку. Разумеется там, где объекты могут быть иммутабельными по своей природе.
Пока это используется там, где по самой логике программы мы имеем работу с такими объектами и понятиями — функциональное программирование вполне неплохо.
А вот когда этот подход начинают использовать там, где он явно ни к чему — получается ерунда. Когда изо всех сил пытаются вычленить и пристроить функцию там, где ей совсем не место, когда пытаются изо всех сил устроить иммутабельность для принципиально изменяющихся объектов, придумывают для этого алгоритмы и структуры данных, которые в итоге оказываются сложнее и запутаннее — получается ерунда.
В общем, все хорошо в меру, и не сотвори себе кумира.
Здравствуйте, Privalov, Вы писали:
I>>Даже во времена 8086 ее мало кто использовал
P>Причем в том коде, который я видел, loop использовали практически исключительно для организации пустых циклов — задержать выполнение.
Собственно дело в том, что loop гвоздями прибит к регистру CX. Из за этого тело цикла, как правило, удлинняется на две команды — push cx и pop cx, если, скажем, нужно вызвать хоть какую нибудь процедуру. Т.е. на ровном месте два дополнительных обращения к памяти.
Здравствуйте, Mamut, Вы писали:
M>На практике ничего неестественного в хвостовой рекурсии нет. И на практике в подавляющем количестве задач все упрется в базу/сеть/скорость записи на диск быстрее, чем оно упрется в проблемы со производительностью ФП
На практике в любой большой системе всегда найдется значительная часть важного функционала, которая упирается именно в процессор-шину. Часть задач вообще требуют исключительно процессор-шину, например обработка звука-видео-сигналов, вычисления и тд.
Здесь экзотика навроде Эрланга сосёт не нагибаясь, как раз потому, что в чистом виде Эрланг нежизнеспособен, ему нужна конская платформа, которая фактически особая ОС поверх имеющейся ОС.
Вот в случае с сетью, всякими событийными моделями, где процессор не является узким местом ФП и Эрланг в т.ч. вполне себе неплох. Но вообще говоря и в этой области у ФП слишком много конкурентов, при чем настолько, что и здесь ФП в меньшинстве.
Здравствуйте, Mamut, Вы писали:
M>Да. Неэффективный код может быть. Да, например у того же Erlang'а проблемы вообще с архитектурой современных машин, и Erlang VM — это, по сути, самостоятельная ОС, мало имеющая отношения к тому, что под ней.
M>И? Дальше что? Это все равно — теоретические изыски. На практике надо смотреть реальные задачи и доатсточно ли нам этой скорости.
Ну вот ты сам себе ответил, почему у Эрланга очень и очень узкая ниша — "у того же Erlang'а проблемы вообще с архитектурой современных машин"