¿Por qué algunos lenguajes funcionales necesitan memoria transaccional de software?

24

Los lenguajes funcionales, por definición, no deben mantener variables de estado. ¿Por qué, entonces, Haskell, Clojure y otros proporcionan implementaciones de software de memoria transaccional (STM)? ¿Hay un conflicto entre dos enfoques?

Michael Spector
fuente
Solo me gustaría vincular este interesante artículo que explica bastante.
Falcon
1
Para ser claros, todos los lenguajes funcionales mantienen el estado, pero la pureza dicta que el valor de una variable no cambia una vez que se establece.
Robert Harvey

Respuestas:

13

No hay nada de malo en que un lenguaje funcional mantenga un estado mutable. Incluso los lenguajes funcionales "puros" como Haskell necesitan mantener el estado para interactuar con el mundo real. Los lenguajes funcionales "impuros" como Clojure permiten efectos secundarios que pueden incluir el estado mutante.

El punto principal es que los lenguajes funcionales desalientan el estado mutable a menos que realmente lo necesite . El estilo general es programar usando funciones puras y datos inmutables, y solo interactuar con el estado mutable "impuro" en las partes específicas de su código que lo requieren. De esa manera, puede mantener el resto de su base de código "puro".

Creo que hay varias razones por las cuales STM es más común en lenguajes funcionales:

  • Investigación : STM es un tema de investigación candente, y los investigadores del lenguaje de programación con frecuencia prefieren trabajar con idiomas funcionales (un tema de investigación en sí mismos, además es más fácil crear "pruebas" sobre el comportamiento del programa)
  • El bloqueo no compone : STM puede verse como una alternativa a los enfoques de concurrencia basados ​​en el bloqueo, que comienzan a tener problemas cuando se escala a sistemas complejos al componer diferentes componentes. Esta es posiblemente la razón principal "pragmática" para STM
  • STM encaja bien con la inmutabilidad : si tiene una estructura inmutable grande, debe asegurarse de que permanezca inmutable, por lo que no desea que ingrese otro subproceso y mute algún subelemento. Del mismo modo, si puede garantizar la inmutabilidad de dicha estructura de datos, puede tratarla de manera confiable como un "valor" estable en su sistema STM.

Personalmente, me gusta el enfoque de Clojure de permitir la mutabilidad, pero solo en el contexto de "referencias administradas" estrictamente controladas que pueden participar en transacciones STM. Todo lo demás en el lenguaje es "puramente funcional".

  ;; 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

Tenga en cuenta que el código anterior es totalmente transaccional y atómico: un observador externo que lea los dos saldos dentro de otra transacción siempre verá un estado atómico constante, es decir, los dos saldos siempre sumarán 200. Con la concurrencia basada en el bloqueo, este es un problema sorprendentemente difícil. para resolver en un sistema complejo grande con muchas entidades transaccionales.

Para una iluminación adicional, Rich Hickey hace un excelente trabajo al explicar el STM de Clojure en este video

mikera
fuente
3

Los lenguajes funcionales, por definición, no deberían mantener variables de estado

Tu definición es incorrecta. El lenguaje que no puede mantener el estado simplemente no se puede usar.

La diferencia entre los lenguajes funcionales e imperativos no es que uno de ellos tenga estado y el otro no. Es en cierto modo que mantienen el estado.

Los lenguajes imperativos tienen un estado extendido por todo el programa.

Los lenguajes funcionales aíslan y mantienen el estado explícitamente mediante firmas de tipo. Y esa es la razón por la que proporcionan mecanismos sofisticados de gestión del estado como STM.

Vagif Verdi
fuente
2

A veces, un programa requiere un estado mutable (por ejemplo, contenido de la base de datos para una aplicación web) y sería genial poder usarlo sin perder los beneficios de la programación funcional. En lenguajes no funcionales, el estado mutable impregna todo. Si lo hace explícito con algún tipo de API especial , puede limitarlo a una pequeña región identificable mientras todo lo demás sigue siendo puramente funcional. Los beneficios de FP incluyen una depuración más fácil, pruebas unitarias repetibles, concurrencia indolora y compatibilidad multinúcleo / GPU.

Will Ware
fuente
Probablemente te refieres al estado mutable. Todos los programas mantienen el estado, incluso los funcionales.
Robert Harvey
Tienes razón. Claramente, no estoy pasando suficiente tiempo haciendo programación funcional, para haberme perdido eso.
Will Ware