Каковы побочные эффекты в предикатах и почему они плохие?
Мне интересно, что считается побочным эффектом в предикатах для fn
как remove
или же filter
, Там, кажется, есть ряд возможностей. Понятно, что если предикат пишет в файл, это побочный эффект. Но рассмотрим ситуацию, подобную этой:
(def *big-var-that-might-be-garbage-collected* ...)
(let [my-ref *big-var-that-might-be-garbage-collected*]
(defn my-pred
[x]
(some-operation-on my-ref x)))
Даже если some-operation-on
это просто запрос, который не меняет состояние, тот факт, что my-pred
сохраняет ссылку на *big...
изменяет состояние системы так, что большая переменная не может быть собрана сборщиком мусора. Это также считается побочным эффектом?
В моем случае я хотел бы написать в систему ведения журнала в предикате. Это побочный эффект?
И почему именно побочные эффекты в предикатах не поощряются? Это потому что filter
а также remove
и их друзья работают лениво, так что вы не можете определить, когда вызываются предикаты (и, следовательно, когда происходят побочные эффекты)?
3 ответа
GC обычно не учитывается при оценке, является ли функция чистой или нет, хотя многие действия, которые делают функцию нечистой, могут иметь эффект GC.
Ведение журнала является побочным эффектом, как и изменение любого состояния в программе или мире. Чистая функция берет данные и возвращает данные, ничего не изменяя.
https://softwareengineering.stackexchange.com/questions/15269/why-are-side-effects-considered-evil-in-functional-programming описывает, почему побочных эффектов избегают в функциональных языках.
Например,
(first (filter odd? (range 20)))
; 1
Но если мы устроим odd?
вывести его аргумент по ходу дела:
(first (filter #(do (print %) (odd? %)) (range 20)))
Будет печатать 012345678910111213141516171819
перед возвращением 1
!
Причина в том, что filter
где это возможно, имеет дело со своим аргументом последовательности в кусках 32 элементов.
Если мы возьмем предел от range
:
(first (filter #(do (print %) (odd? %)) (range)))
... мы получаем полноразмерный чанк: 012345678910111213141516171819012345678910111213141516171819202122232425262728293031
Просто печать аргумента сбивает с толку. Если побочные эффекты значительны, все может пойти не так, как надо.
Проблема состоит в том, чтобы определить, когда или даже возникнут ли побочные эффекты при любом вызове функции.
Если вам важно, чтобы одни и те же входные данные возвращали один и тот же ответ, у вас все в порядке. Побочные эффекты зависят от того, как выполняется функция.