Как функциональные языки моделируют побочные эффекты? - PullRequest
21 голосов
/ 03 октября 2010

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

Ответы [ 3 ]

22 голосов
/ 03 октября 2010

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

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

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

Их можно использовать так:

let main w =
  let w1 = print ("What's 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's your name?", w) in
  let (str, w2) = read w in
  let w3 = print ("Your name is " ^ name, w2) in
  w3

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

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

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

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

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

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

Пример сверху выглядел бы так с монадическим IO:

let main =
  (print "What's your name?") >>=
  (lambda () -> read >>=
  (lambda name -> print ("Your name is " ^ name)))
12 голосов
/ 03 октября 2010

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

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

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

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

1 голос
/ 03 октября 2010

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

...