Комментарии 18
У меня только один контр-аргумент — против чистоты функций обычно играет производительность. (см. «garbage collector friendly javascript»)
Сначала называем сложным и неудобным DI (который в реальном мире, а не академических примерах выполняется автоматом), а потом наворачиваем километры других абстракций, которые делают «чисто» и удобно… Ну ок.
Про производительность тоже лучше умолчать.
Про производительность тоже лучше умолчать.
На середине статьи были мысли примерно такие же. "Открыто новое достижение: 95% функций — чистые!", "в JS нет глобальных моков?!".
Но потом с раздела "Зачем это всё?" автор объясняет, как чистые функции помогают при дебаге. Мне это показалось довольно убедительным и полезным. Если рассуждать дальше, то появляются вопросы по сравнению приложения, написаного на чистых функциях, и приложения, написаного с качественным ООП:
- насколько дебаг проще?
- какое сравнение трудозатрат на дальней дистанции?
- чему проще научить, и какой подход проще внедрить, с учетом того, что в большинстве ЯП нет проверки чистоты функций?
- что выгоднее для бизнеса?
Странно всё это. На сколько я понимаю концепция состоит не в том чтобы отложить вычисления с побочными эффектами, а в том чтобы отделить их.
Если тебе нужно что-то из IO достань его, а потом положи в чистую функцию.
Если тебе нужно что-то из IO достань его, а потом положи в чистую функцию.
Это одно и то же. Чтобы их отложить — их надо отделить, а чтобы их отделить — их надо отложить.
Нет это не одно и тоже. Всё что вычисляется в монаде IO имеет доступ к побочным эффектам ввода-вывода.
сравните
и
сравните
c<-getChar
c'<-return.toUpper $ c
putChar c'
и
c<-getChar
let c'=toUpper c
putChar c'
И что же вы хотите этим сказать? И при чем тут откладывание и отделение?
Если вы выполняете вычисление в монаде, то оно имеет доступ к побочным эффектам этой монады.
В первом варианте при вычислении c' может произойти всё что угодно, поскольку оно выполняется в IO (надеюсь то, что на месте return.to Upper может быть любое вычисление вида IO Char понятно).
Если вы засунете калбек с типом IO a глубоко внутрь вычисления и захотите там достать из него a, то у Вас всё вычисление будет в монаде IO, и гарантировать что там кроме Вашего калбека больше ничего не произошло вы не сможете.
Таким образом внутрь чистого вычисления, чтобы оно оставалось чистым, можно передавать только иммутабельные аргументы.
В первом варианте при вычислении c' может произойти всё что угодно, поскольку оно выполняется в IO (надеюсь то, что на месте return.to Upper может быть любое вычисление вида IO Char понятно).
Если вы засунете калбек с типом IO a глубоко внутрь вычисления и захотите там достать из него a, то у Вас всё вычисление будет в монаде IO, и гарантировать что там кроме Вашего калбека больше ничего не произошло вы не сможете.
Таким образом внутрь чистого вычисления, чтобы оно оставалось чистым, можно передавать только иммутабельные аргументы.
То есть, если мы решили отделить «чистые» вычисления от «нечистых», альтернативы методу внедрения зависимостей нет?
Об этом я не подумал. Но, можно ещё внедрять зависимости наоборот. Вставлять калбеки из чистых функций в монадические вычисления. Тогда, если дело ограничивается return.f, то можно давать некоторые гарантии. Но, как только вы заменили сигнатуру f с возвращающей a на IO а, так сразу возможен биг бадамум.
Это все понятно. Но где в этих примерах разница между откладыванием и отделением?
Ну как бы оборачивая ф-цию с побочными эффектами в thunk(отложенная ф-ция) мы получаем:
1.чистую фунцию;
2.отделяем ф-цию c эффектами от чистых, так как ее не получится просто так вызвать не
дергая ф-цию обертку.
Принцип разделяй и властвуй в полном смысле тут работает.
Вот и все жульничество как пишет автор.
Где то читал что монада IO в Haskelle реализована через thunk-и, ссылку не могу найти к сожалению.
1.чистую фунцию;
2.отделяем ф-цию c эффектами от чистых, так как ее не получится просто так вызвать не
дергая ф-цию обертку.
Принцип разделяй и властвуй в полном смысле тут работает.
Вот и все жульничество как пишет автор.
Где то читал что монада IO в Haskelle реализована через thunk-и, ссылку не могу найти к сожалению.
Интересно было почитать
Отвечаю на опрос: пользуюсь концепциями функционального программирования в своих проектах
Отвечаю на опрос: пользуюсь концепциями функционального программирования в своих проектах
Кладем чистые функции в чистые ES-модули, и где все сайд эффекты — зависимости модуля, и радостно мокаем все эти внешние зависимости в ноль, получая возможность тестировать конечный код в реальном вакууме, не теряя статический анализ и типизацию.
Здравствуйте, что-то не работает join
Вроде вот такая конструкция работает, или как правильно? Спасибо.
join(x) {
return f(x);
}
</code>
он возвращает значение и как бы уже цепочка после него работать не будет.
<source lang="javascript">
const userBioHTML = Effect.of(window)
.map(x => x.myAppConf.selectors['user-bio'])
.map($)
.join()
.map(x => x.innerHTML);
Вроде вот такая конструкция работает, или как правильно? Спасибо.
join(x) {
const j = this.runEffects(x);
return Effect(() => j);
},
Перечитал, подумал, ещё раз перечитал, взял карандаш.
Это не IO. Это — Reader.
Это не IO. Это — Reader.
Читаю переводы статей от компании RUVDS, и кажется, что там настолько хорошо построили производственный процесс, что все само работает, ничего не ломается, и есть время на то, чтобы переводить статьи )
Эта статья, имхо, хорошая. TL;DR: «глобальное состояние сложно держать в уме и сложно отлаживать; функциональное программирование — это подход, который позволяет разложить глобальное состояние программы на маленькие и поэтому _понятные_ фрагменты»
Эта статья, имхо, хорошая. TL;DR: «глобальное состояние сложно держать в уме и сложно отлаживать; функциональное программирование — это подход, который позволяет разложить глобальное состояние программы на маленькие и поэтому _понятные_ фрагменты»
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Борьба с грязными побочными эффектами в чистом функциональном JavaScript-коде