Побочные эффекты - это хорошо? - PullRequest
28 голосов
/ 18 апреля 2009

Я чувствую термин довольно уничижительный. Следовательно, я поражен двумя предложениями в Википедии:

Императивное программирование известно используя побочные эффекты, чтобы сделать программы работают. функциональная программирование в свою очередь известно своим минимизация побочных эффектов. [1]

Поскольку я немного пристрастен к математике, последний звучит превосходно Каковы аргументы для побочных эффектов? Они означают потерю контроля или принятие неопределенности? Они хорошая вещь?

Ответы [ 13 ]

51 голосов
/ 20 апреля 2009

Время от времени я вижу вопрос о SO, который заставляет меня тратить полчаса на редактирование действительно плохой статьи в Википедии. Статья сейчас только в меру плохая. В той части, которая касается вашего вопроса, я написал следующее:

В информатике функция или выражение, как говорят, имеют побочный эффект , если, помимо создания значения, они также изменяют некоторое состояние или имеют наблюдаемое взаимодействие с вызывающие функции или внешний мир. Например, функция может изменить глобальную или статическую переменную, изменить один из ее аргументов, вызвать исключение, записать данные в экран или файл, прочитать данные, вызвать другие побочные функции или запустить ракеты. При наличии побочных эффектов поведение программы зависит от прошлой истории; то есть порядок оценки имеет значение. Поскольку понимание эффективной программы требует обдумывания всех возможных историй, побочные эффекты часто затрудняют понимание программы.

Побочные эффекты необходимы для взаимодействия программы с внешним миром (людьми, файловыми системами, другими компьютерами в сети). Но степень использования побочных эффектов зависит от парадигмы программирования. Императивное программирование известно неконтролируемым, беспорядочным использованием побочных эффектов. В функциональном программировании побочные эффекты используются редко. Функциональные языки, такие как Standard ML и Scheme, не ограничивают побочные эффекты, но программисты обычно избегают их. Функциональный язык Haskell ограничивает побочные эффекты статической системой типов; только функция, которая выдает результат типа IO, может иметь побочные эффекты.

25 голосов
/ 19 апреля 2009

Побочные эффекты - необходимое зло , и нужно стремиться минимизировать / локализовать их.

В других комментариях к этой теме говорится, что безэффектное программирование иногда не является интуитивным , но я думаю, что то, что люди считают «интуитивным», во многом является результатом их предыдущего опыта, и опыт большинства людей имеет тяжелый императивный уклон. Основные инструменты становятся все более функциональными с каждым днем, потому что люди обнаруживают, что программирование без эффектов приводит к меньшему количеству ошибок (хотя по общему признанию иногда новый / другой класс ошибок) из-за меньшей вероятности взаимодействия отдельных компонентов через эффекты.

Почти никто не упоминал о производительности, а программирование без эффектов обычно имеет худшую производительность , чем эффективное, поскольку компьютеры - это машины фон Неймана, которые предназначены для эффективной работы с эффектами (а не для работы хорошо с лямбдами). Теперь, когда мы находимся в разгар многоядерной революции, это может изменить игру, так как люди обнаруживают, что им нужно использовать преимущества ядер, чтобы получить производительность, и в то время как распараллеливание иногда требует от ученого-ракетостроителя полного эффекта, это может быть легко сделать правильно, когда вы без эффекта.

17 голосов
/ 18 апреля 2009

В машинах фон-Неймана побочные эффекты - это то, что заставляет машину работать. По сути, независимо от того, как вы пишете свою программу, для ее работы потребуется побочный эффект (на низком уровне просмотра).

Программирование без побочных эффектов означает абстрагирование побочных эффектов, чтобы вы могли думать о проблеме в целом - не беспокоясь о текущем состоянии машины - и уменьшать зависимости между различными модулями программы (будь то процедуры, классы или что-то еще) еще). Тем самым вы сделаете вашу программу более пригодной для повторного использования (поскольку модули не зависят от конкретного состояния для работы).

Так что да, программы без побочных эффектов - это хорошо, но побочные эффекты просто неизбежны на некотором уровне (поэтому их нельзя рассматривать как "плохие").

9 голосов
/ 18 апреля 2009

Pro:

  • В конце концов побочные эффекты - это то, чего вы хотите достичь.
  • Побочные эффекты естественны для кода, взаимодействующего с внешним миром.
  • Они делают многие алгоритмы простыми.
  • Чтобы избежать использования побочных эффектов, вам необходимо реализовать циклы с помощью рекурсии, поэтому ваша языковая реализация требует оптимизации хвостового вызова.

Con:

  • Чистый код легко распараллелить.
  • Побочные эффекты могут усложнить код.
  • Чистый код проще доказать.

Например, Haskell, поначалу он кажется очень элегантным, но затем вам нужно начать играть с внешним миром, и это уже не так весело. (Haskell перемещает состояние в качестве параметра функции и скрывает его в вещи, называемые монады, которые позволяют писать в стиле императивного стиля.)

7 голосов
/ 26 апреля 2010

Побочные эффекты такие же, как и у любого другого оружия. Они, несомненно, полезны и потенциально очень опасны при неправильном обращении.

Как и у оружия, у вас есть побочные эффекты всех видов всех степеней летальности.

В C ++ побочные эффекты абсолютно неограничены благодаря указателям. Если переменная объявлена ​​как «приватная», вы все равно можете получить к ней доступ или изменить ее, используя приемы указателей. Вы даже можете изменять переменные, которые не находятся в области видимости, такие как параметры и локальные параметры вызывающей функции. С небольшой помощью операционной системы (mmap) вы даже можете изменить машинный код вашей программы во время выполнения! Когда вы пишете на таком языке, как C ++, вы повышены до уровня Бит-бога, мастера всей памяти в вашем процессе. Все оптимизации, которые компилятор вносит в ваш код, сделаны при условии, что вы не злоупотребляете своими полномочиями.

В Java ваши возможности более ограничены. Все переменные в области видимости находятся под вашим контролем, включая переменные, используемые разными потоками, но вы всегда должны придерживаться системы типов. Тем не менее, благодаря тому, что в вашем распоряжении есть подмножество ОС и наличие статических полей, ваш код может иметь нелокальные эффекты. Если отдельный поток как-то закрывает System.out, это будет похоже на магию. И это будет магией: магия побочного действия.

У Haskell (несмотря на пропаганду о чистоте) есть монада IO, которая требует, чтобы вы зарегистрировали все свои побочные эффекты в системе типов. Включение вашего кода в монаду ввода / вывода похоже на трехдневный период ожидания для пистолетов: вы все равно можете отмахнуться, но только после того, как вы согласитесь с правительством. Также есть unsafePerformIO и тому подобное, которые являются черным рынком Haskell IO, предоставляя вам побочные эффекты без вопросов.

Миранда, предшественница Haskell, является чисто функциональным языком, созданным до того, как монады стали популярными. Миранда (насколько я узнал ... если я ошибаюсь, заменим лямбда-исчисление) вообще не имеет IO-примитивов. Единственный ввод-вывод - это компиляция программы (входные данные), запуск программы и печать результата (выходных данных). Здесь у вас есть полная чистота. Порядок исполнения совершенно не имеет значения. Все «эффекты» являются локальными для функций, которые их объявляют, то есть никогда не могут две непересекающиеся части кода влиять друг на друга. Это утопия (для математиков). Или, что то же самое, дистипия. Это скучно. Ничего не происходит Вы не можете написать сервер для этого. Вы не можете написать ОС в нем. Вы не можете написать SNAKE или Tetris в нем. Все просто сидят и смотрят математически.

7 голосов
/ 18 апреля 2009

Без побочных эффектов вы просто не сможете делать определенные вещи. Одним из примеров является ввод / вывод, поскольку появление сообщения на экране по определению является побочным эффектом. Вот почему целью функционального программирования является минимизация побочных эффектов, а не их полное устранение.

Если оставить в стороне, часто бывают случаи, когда минимизация побочных эффектов вступает в конфликт с другими целями, такими как скорость или эффективность памяти. В других случаях уже существует концептуальная модель вашей проблемы, которая хорошо согласуется с идеей мутирующего состояния, и борьба с этой существующей моделью может привести к потере энергии и усилий.

6 голосов
/ 18 апреля 2009

Жюри все еще отсутствует. И судебное разбирательство продолжается с самого начала компьютерных технологий, так что не ждите вердикта в ближайшее время.

3 голосов
/ 20 апреля 2009

Это правда, как некоторые люди здесь упоминают, что без побочных эффектов нельзя сделать полезное приложение. Но из этого не следует, что использование побочных эффектов неконтролируемым образом - это хорошо.

Рассмотрим следующую аналогию: процессор с набором команд, у которого нет команд ветвления, будет абсолютно бесполезным. Однако из этого не следует, что программисты должны постоянно использовать goto s. Напротив, оказалось, что структурированное программирование и более поздние языки ООП, такие как Java, могут обойтись даже без оператора goto, и никто его не пропустил.

(Конечно, в Java все еще есть goto - теперь она называется break , continue и throw .)

3 голосов
/ 18 апреля 2009

Побочные эффекты необходимы для значительной части большинства применений. Чистые функции имеют много преимуществ. О них легче думать, потому что вам не нужно беспокоиться о предварительных и постусловиях. Так как они не меняют состояние, их легче распараллелить, что станет очень важным при увеличении числа процессоров.

Побочные эффекты неизбежны. И их следует использовать всякий раз, когда они являются лучшим выбором, чем более сложное, но чистое решение. То же самое касается чистых функций. Иногда к проблеме лучше подойти с помощью функционального решения.

Все хорошо =) Вы должны использовать разные парадигмы в зависимости от решаемой проблемы.

1 голос
/ 17 июня 2015

Поскольку ваша программа должна иметь побочные эффекты, чтобы иметь какой-либо выходной или интересный эффект (кроме нагрева вашего процессора), вопрос скорее в том, где эти побочные эффекты должны запускаться в вашей программе. Они становятся вредными, только если они скрыты в методах, которые вы не ожидаете от них.

Как правило: разделяйте чистые методы и методы с побочными эффектами. Метод, который выводит что-то на консоль, должен делать только это и не вычислять какое-либо интересное значение, которое вы, возможно, захотите использовать где-то еще.

...