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

Я пытаюсь понять основную концепцию функциональных языков:

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

http://www.haskell.org/haskellwiki/Why_Haskell_matters#Functions_and_side-effects_in_functional_languages

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

Какой наиболее распространенный шаблон используется, чтобы обойти или решить эту проблему?


person Allyl Isocyanate    schedule 06.12.2011    source источник


Ответы (3)


Наиболее распространенный шаблон для работы с побочными эффектами и нечистотами в функциональных языках:

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

Примеры:

  • Лисп/Схема: set!
  • Clojure: refs и использование мутирующих методов для java-объектов
  • Scala: создание переменных с помощью var
  • ML: не уверен в деталях, но Википедия говорит, что допускает некоторую нечистоту

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

Но решение Haskell, ИМХО, не самое распространенное.


(1) Не уверен в деталях здесь. Спасибо CAMcCann за указание на то, что эта метафора используется слишком часто и, возможно, не совсем точна.

person Matt Fenwick    schedule 06.12.2011
comment
Как бы то ни было, на самом деле работают вещи в Haskell не так, хотя это часто используемая метафора. На самом деле происходит лишь то, что система типов используется для того, чтобы нечистые функции помечались как таковые и выполнялись в строго определенном порядке. В реализации этого используется метафора преходящего состояния вселенной, но концептуально она не выдерживает критики при ближайшем рассмотрении. - person C. A. McCann; 07.12.2011
comment
Вселенная заставляет его казаться сложнее, чем он есть, для его контекста, который является БД. Это вполне возможно, и если вы используете источник событий, вы также можете получить состояние в прошлом. Ресурсоемкий, но мы говорим здесь о функциональном. - person Justin Dennahower; 30.08.2016

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

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

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

main:
  read contents of abc.txt into mystring
  write contents of mystring to def.txt

Приведенная выше процедура main представляет собой ряд шагов, описывающих выполнение ряда действий.

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

main = the reading of abc.txt into mystring followed by
       the writing of mystring to def.txt

Итак, main — это выражение, которое при вычислении возвращает действие, описывающее, что нужно сделать, чтобы выполнить программу. Фактическое выполнение этого действия происходит за пределами мира программистов. И это действительно так; ниже приведена реальная программа на Haskell, которую можно скомпилировать и запустить:

main = readFile "abc.txt" >>= \ mystring ->
       writeFile "def.txt" mystring

Можно сказать, что a >>= b означает «действие a, за которым следует результат a, переданный действию b» в этой ситуации, а результатом оператора являются объединенные действия a и b. Вышеприведенная программа, конечно, не идиоматична на языке Haskell; можно переписать его следующим образом (удалив лишнюю переменную):

main = readFile "abc.txt" >>=
       writeFile "def.txt"

... или, используя синтаксический сахар и do-нотацию:

main = do
  mystring <- readFile "abc.txt"
  writeFile "def.txt" mystring

Все вышеперечисленные программы не только эквивалентны, но и идентичны с точки зрения компилятора.

Вот как файлы, системы баз данных и веб-серверы могут быть написаны как чисто функциональные программы: путем потоковой передачи значений действий через программу, чтобы они объединялись и, наконец, оказывались в функции main. Это дает программисту огромный контроль над программой, и именно поэтому чисто функциональные языки программирования так привлекательны в некоторых ситуациях.

person dflemstr    schedule 06.12.2011

Доступ к базе данных ничем не отличается от других случаев ввода-вывода, таких как print(17).

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

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

Некоторые языки, такие как Clean, используют типы уникальности для обеспечения той же последовательности, что и Haskell для монад, но такие языки в настоящее время найти труднее.

person hugomg    schedule 06.12.2011