Как функциональные языки моделируют побочные эффекты?

Поскольку побочные эффекты нарушают ссылочную прозрачность, не противоречат ли они функциональным языкам?

Ответы

Ответ 1

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

1) Тип мира, представляющий внешнее состояние, где каждое значение этого типа гарантируется системой типов, которая будет использоваться только один раз.

В языке, использующем этот подход, функции print и read могут иметь типы (string, world) -> world и world -> (string, world) соответственно.

Они могут быть использованы следующим образом:

let main w =
  let w1 = print ("What your name?", w) in
  let (str, w2) = read w1 in
  let w3 = print ("Your name is " ^ name, w2) in
  w3

Но не так:

let main w =
  let w1 = print ("What your name?", w) in
  let (str, w2) = read w in
  let w3 = print ("Your name is " ^ name, w2) in
  w3

(поскольку w используется дважды)

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

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

2) Монада IO, где все операции с побочными эффектами должны выполняться внутри этой монады.

При таком подходе все операции с побочными эффектами будут иметь тип io something. Например, print будет функцией с типом string -> io unit, а read будет иметь тип io string.

Единственный способ получить доступ к значению выполняемой операции будет заключаться в использовании операции "monadic bind" (например, → = в haskell) с операцией ввода-вывода в качестве одного аргумента и функцией, описывающей, что делать с результатом как другой операнд.

Приведенный выше пример будет похож на это с монадическим IO:

let main =
  (print "What your name?") >>=
  (lambda () -> read >>=
  (lambda name -> print ("Your name is " ^ name)))

Ответ 2

Существует несколько вариантов обработки ввода-вывода на функциональном языке.

  • Не будь чистым. Многие функциональные языки не являются чисто функциональными. Более того, они поддерживают а не обеспечивать его соблюдение. Это, безусловно, наиболее распространенное решение проблемы ввода-вывода в функциональном программировании. (Примеры: Lisp, схема, стандартный ML, Erlang и т.д.).
  • Преобразование потока. Ранний ввод-вывод Haskell был выполнен таким образом. Проверьте мою ссылку ниже, если вы хочу больше информации. (Подсказка: вы, вероятно, этого не делаете.)
  • Продолжающий передачу ввода-вывода ( "переходящий мир", упомянутый в других ответах). В этом вы передаете токен данных вокруг вашего ввода-вывода, который действует как необходимое "другое значение" для сохранения ссылочной целостности в живых. Это используется несколькими диалектами ML, если память служит.
  • "Продолжение" или "мировая" вещь выше может быть обернута в различные типы данных, большинство (в) известных использование монад в этой роли в Haskell. Обратите внимание, что это, по-видимому, то же самое в обложки, но угасание следа переменных состояния "мир" / "продолжение" удаляется.

Там исследовательская диссертация, которая исчерпывающе анализирует их.

Функциональный ввод-вывод - это постоянная область исследований, и есть другие языки, которые затрагивают этот вопрос интересными и увлекательными способами. Логика Хора используется для использования на некоторых языках исследования. Другие (например, Mercury) используют уникальность ввода. Третьи (например, Clean) используют системы эффектов. Из них у меня очень ограниченное воздействие только на Меркурий, поэтому я не могу комментировать подробности. Там бумага, в которой подробно описывается система чистого ввода-вывода, однако, если вы заинтересованы в этом направлении.

Ответ 3

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