Почему некоторым функциональным языкам нужна программная транзакционная память?

24

Функциональные языки по определению не должны поддерживать переменные состояния. Почему же тогда Haskell, Clojure и другие предоставляют реализации программной транзакционной памяти (STM)? Есть ли конфликт между двумя подходами?

Майкл Спектор
источник
Я просто хотел бы связать эту интересную статью, которая многое объясняет.
Сокол
1
Чтобы было понятно, все функциональные языки поддерживают состояние, но чистота диктует, что значение переменной не изменяется после ее установки.
Роберт Харви

Ответы:

13

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

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

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

  • Исследование : STM - горячая тема исследования, и исследователи языка программирования часто предпочитают работать с функциональными языками (тема исследования сама по себе, плюс легче создавать «доказательства» о поведении программы)
  • Блокировка не создает : STM можно рассматривать как альтернативу основанным на блокировке подходам к параллелизму, что приводит к проблемам при масштабировании до сложных систем путем компоновки различных компонентов. Это, пожалуй, главная «прагматическая» причина для СТМ
  • STM хорошо сочетается с неизменяемостью : если у вас большая неизменяемая структура, вы хотите убедиться, что она остается неизменной, поэтому вы не хотите, чтобы какой-то другой поток входил и изменял какой-то подэлемент. Аналогично, если вы можете гарантировать неизменность указанной структуры данных, вы можете надежно рассматривать ее как стабильную «ценность» в вашей системе STM.

Мне лично нравится подход Clojure, допускающий изменчивость, но только в контексте строго контролируемых «управляемых ссылок», которые могут участвовать в транзакциях STM. Все остальное в языке "чисто функционально".

  ;; define two accounts as managed references
  (def account-a (ref 100))
  (def account-b (ref 100))

  ;; define a transactional "transfer" function
  (defn transfer [ref-1 ref-2 amount]
    (dosync
      (if (>= @ref-1 amount)
        (do 
          (alter ref-1 - amount)
          (alter ref-2 + amount))
        (throw (Error. "Insufficient balance!")))))

  ;; make a stranfer
  (transfer account-a account-b 75)

  ;; inspect the accounts
  @account-a
  => 25

  @account-b
  => 175

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

Для некоторого дополнительного просветления Рич Хикки отлично объясняет STM Clojure в этом видео.

mikera
источник
3

Функциональные языки по определению не должны поддерживать переменные состояния

Ваше определение неверно. Язык, который не может поддерживать состояние, просто не может быть использован.

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

Императивные языки имеют государственное распространение по всей программе.

Функциональные языки изолируют и поддерживают состояние явно через сигнатуры типов. И именно поэтому они предоставляют сложные механизмы управления состоянием, такие как STM.

Вагиф Верди
источник
2

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

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