TarasB
> где-где?
Да "упрощал" ты там тоже через переголову. Чуть ли не через макросы FOR_EACH_ITER.
=A=L=X=
А, это где я от копипасты избавлялся-то?
Да, показательно.
Как сказали на ГК, "паттерн - это когда 20 одинаковых копипастных строк заменяются на 40 разных"
Кстати да, это помогло мне сформировать мысль почему ФП с определенного момента меня начинает раздражать.
Потому что постоянно код обрывается отсылкой в какое то другое место или рекурсию. Множество точек следования, где надо мозгом сказать "стоп, тут надо запомнить состояние и перепрыгнуть в другое место, что там происходит смотреть". И в силу эдакой специфичной рекурсионности постоянно куда то перепрыгиваешь мозгом, потом возвращаешся, потом снова прыгаешь, нелинейное очень повествование всё время сбивающее с толку и напрягающее память. Не спорю этому видимо надо научится и натренироваться.
В обычной импертивщине я наоборот выработал привычку "линеаризировать" код, т.е. вместо:
if (... ) { if ( .... ) { if ( ... ) { ... }; } };
что начинает не просто фигачить отступами, а начинает напрягать "надо помнить в каком уровне вложенности мы находимся и в чём её цель заключается и куда мы попадём если выйдем наружу на один уровень", то я это резко не привествую и переформатирую на что то типа:
if (... ) { } else goto end; if ( .... ) { } else goto end;
Ну по ситуации конечно. Т.е. вложенность мне не нравится даже на уровне простых каких то вложенных конструкций. И я привык именно что "линеаризировать" код чтобы упрощать его восприятие.
В ФП же наоборот - рекурсия - это самая суть техники и линеаризация просто отсутствует как класс. Вечно надо мозг стеком напрягать. Вот это вот не нравилось никогда - и это одна из причин почему шаблонный код после какой то тоже степени крутости меня начинает раздражать.
=A=L=X=
> code bloat вокруг непоятно чего
Я сторонник самодокументирующегося кода. Названия должны быть достаточно понятными, чтобы не писать комментарии. Писать комментарии вообще плохо, тк обязательно их кто-то не прочитает, нарушит требования написанные в них, потеряет, сдвинет от реального кода (который они описывали) или забудет их исправить после исправления. А как известно хуже отсутствия данных только неверные данные. Тк как код с комментариями не компилируетя, то и люди на комментарии редко обращают внимание и редко следят за корректностью. С мелкими правильно названными функциями с расставленными ассертами - таких проблем почти нет.
По сути разбиваем на функции не только ради убирания копипасты, но и ради комментирования кода. Одна функция - одно действие. Это правильная декомпозиция. Если функция больше 9 строк\операций - это говорит о том, что с ней что-то не так. Человек больше 7 ± 2 сущностей\операций не воспринимает. А если функция больше экрана, то это ахтунг. В моём коде выше на крестах есть недостаток в том, что код не побит на модули\классы. Здесь не спорю, поэтому было много разноцелевых сущностей в глобальной области видимости (что противоречит 7 ± 2 сущностей). Это конечно не верно. К своему модулю\классу должны относиться функции, а не перемешаны в кучу. И поэтому это вызвало у вас диссонанс. В том же Хаскеле красиво решена проблема кода, который используется только в одном месте - это where.
имя_функции1 параметры = тело_функции where
локальная_функция_1 = тело_функции
локальная_функция_2 = тело_функции
То есть ненужные много раз функции не будут валяться в глобальной области видимости. В тоже время локальные функции объявлены ниже кода, тк обычно когда вы смотрите функцию - вам хочется в данный момент узнать реализацию функции имя_функции1, а не смотреть на реализацию функций локальная_функция_1 и локальная_функция_2, как это требуют многие современные языки при использовании локальных функций, тк приходится локальные функции определять выше их использования. Это фактически отвлекает от просмотра реализации имя_функции1, тк реализацию локальных функций возможно даже не придется смотреть, если названия локальных функций достаточно самодокументируемы, а параметры очевидны. Заставлять просматривать локальные функции перед реализацией самой функции - верх маразма. Человеку придётся прокручивать вниз функции и с учетом локальных функций возможно довольно длинной. Это по сути отвлекает внимание от основной цели посмотреть реализацию имя_функции1 и заставляет рыскать по коду, тратя время.
Меня долгое время выворачивало от конструкции where, пока не понял зачем она нужна и все её плюсы.
Конечно же локальные функции весьма удобны для реализации самодокументируемого кода, тк не нужно выносить внутренние мелкие функции на всеобщее обозрение. К тому же замыкания локальных функций на контекст основной функции - позволяет использовать другие локальные функции, локальные, переменные, локальные константы и отсутствует необходимость передавать лишние параметры, что сказывается положительно на простоте сигнатур, не громоздкости кода и простоте использования.
laMer007
> Человек больше 7 ± 2 сущностей\операций не воспринимает.
Поэтому я не смог дочитать твой текст.
P.S.
кстати да, мне декларативное описание функций
fact 0 = 0 fact x = x * fact (x-1)
понравилось именно своей линеаризацией. очень линейно выглядит, без вложенных if-ов, тем не менее их содержа перед взглядом прямо в линейном табличном виде.
=A=L=X=
> И в силу эдакой специфичной рекурсионности постоянно куда то перепрыгиваешь мозгом, потом возвращаешся
Рекурсия идёт из математики, метода индукции, дисциплины динамическое программирование и ещё некоторых других. Многие задачи можно решить рассмотрением частных случаев. А если мы не попали ни в один из частных случаев, то задача решается решением нескольких или одной более мелкой подзадачи тем же самым механизмом. Это очень удобно для построения сложных алгоритмов.
=A=L=X=
> мне декларативное описание функций
Ну к дублированию кода это конечно тоже приводит, тк название функции приходиться дублировать, но в целом красиво
А вообще в Хаскеле меня некоторые вещи раздражают.
Уж слишком математично. Там есть абстракции в стандартной библиотеки: моноид, кольцо, поле и тд и тп.
Перегрузки функций нет. Хотя люди в сишке же как-то с этим живут... Впрочем эмуляция через классы типов есть конечно, но имхо как-то громоздко. При этом экземпляр типа - это инстанс всех множественных интерфейсов одновременно.
laMer007
> Рекурсия идёт из
Да это азы алгоритмики, просто обычное процедурное программирование. Я не спорю что дробить, разделять и властвовать - в этом огромная заслуга. Тут просто надо помнить что лекарство в крупных дозах - яд. Слишком мелкое разбиение такое же зло как слишком крупное разбиение.
> Ну к дублированию кода это конечно тоже приводит, тк название функции
> приходиться дублировать
У меня к размерам кода исчезли особые претензии еще после знакомства с перлом - наглядный парашенский язык который поставил своей целью минимизировать количество символов кода, породив при этом знаменитый перл "регулярку проще написать заново, чем понять как она работает и дополнить изменениями".
=A=L=X=
> наглядный парашенский язык который поставил своей целью минимизировать
> количество символов кода
Бугагага это надо тыкать в морду всем любителям дебильной экономии 1 вместо 1.0f ценой потенциальных грабель.
=A=L=X=
> Слишком мелкое разбиение такое же зло как слишком крупное разбиение.
Рекурсивный алгоритм обычно приводит к уменьшению кол-ва операций в коде, который нужно понять. И в этом его плюс, тк понять код с меньшим кол-вом операций легче, чем код с большим.
TarasB
> дебильной экономии 1 вместо 1.0f ценой потенциальных грабель.
А какие проблемы? Думается мне что кресты скастят константу во время оптимизации при компильтайме. И проблем не будет. Скорость на преобразование не будет утеряна.
laMer007
> Рекурсивный алгоритм обычно приводит к уменьшению кол-ва операций в коде,
> который нужно понять. И в этом его плюс, тк понять код с меньшим кол-вом
> операций легче, чем код с большим.
Расскажи это на пару месяцев назад поднятом примере: http://habrahabr.ru/post/118927/
var Y = function (h) {
return (function (f) {
return f(f);
})(function (f) {
return h(function (n) {
return f(f)(n);
});
});
};Я прекрасно понимаю этот JavaScript-синтаксис. По отдельности могу рассказать что каждая строчка делает. Полностью понял концепцию - вернуть функцию возвращающую функцию возвращающую функцию возвращающую - вплоть до нуля - и потом каждая фактически вызывается в раскрытом дереве.
Трассировку мозгом за 2 часа где то суммарных обдумываний так и не получилось этого кода сделать. То ли старею, то ли что.
laMer007
Да, но придётся игнорировать предупреждение компилятора.
=A=L=X=
> Расскажи это на пару месяцев назад поднятом примере
Всё можно довести до абсурда. Никогда не пользовался Y-комбинатором. Объяснение на википедии. Если я правильно помню то работает только в динамически типизированных языках нормально. Ну и синтаксис JS хочется развидеть.
Тема в архиве.