Por que algumas linguagens funcionais precisam de memória transacional de software?


24

Linguagens funcionais, por definição, não devem manter variáveis ​​de estado. Por que, então, Haskell, Clojure e outros fornecem implementações de memória transacional de software (STM)? Existe um conflito entre duas abordagens?


Gostaria apenas de vincular este artigo interessante, que explica bastante.
Falcon

11
Para ser claro, todas as linguagens funcionais mantêm o estado, mas a pureza determina que o valor de uma variável não muda depois que é definido.
Robert Harvey

Respostas:


13

Não há nada de errado em uma linguagem funcional manter um estado mutável. Mesmo linguagens funcionais "puras", como Haskell, precisam manter o estado para interagir com o mundo real. Linguagens funcionais "impuras" como o Clojure permitem efeitos colaterais que podem incluir um estado de mutação.

O ponto principal é que as linguagens funcionais desencorajam o estado mutável, a menos que você realmente precise . O estilo geral é programar usando funções puras e dados imutáveis ​​e interagir apenas com o estado mutável "impuro" nas partes específicas do seu código que o exigem. Dessa forma, você pode manter o restante da sua base de código "pura".

Eu acho que há várias razões pelas quais o STM é mais comum em linguagens funcionais:

  • Pesquisa : STM é um tópico de pesquisa popular, e os pesquisadores da linguagem de programação frequentemente preferem trabalhar com idiomas funcionais (um tópico de pesquisa em si mesmos, além de ser mais fácil criar "provas" sobre o comportamento do programa)
  • Bloquear não compor : o STM pode ser visto como uma alternativa às abordagens de concorrência baseadas em bloqueio, que começam a ter problemas quando você aumenta a escala para sistemas complexos compondo componentes diferentes. Esta é sem dúvida a principal razão "pragmática" para STM
  • O STM se encaixa bem com a imutabilidade : se você tem uma estrutura imutável grande, deseja garantir que ela permaneça imutável, para que você não queira que outro encadeamento entre e modifique algum subelemento. Da mesma forma, se você puder garantir a imutabilidade da referida estrutura de dados, poderá tratá-lo com segurança como um "valor" estável em seu sistema STM.

Pessoalmente, gosto da abordagem de Clojure de permitir a mutabilidade, mas apenas no contexto de "referências gerenciadas" estritamente controladas que podem participar de transações do STM. Todo o resto da linguagem é "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

Observe que o código acima é totalmente transacional e atômico - um observador externo que lê os dois saldos em outra transação sempre verá um estado atômico consistente, ou seja, os dois saldos sempre somam 200. Com a concorrência baseada em bloqueio, esse é um problema surpreendentemente difícil resolver em um grande sistema complexo com muitas entidades transacionais.

Para uma iluminação extra, Rich Hickey faz um excelente trabalho ao explicar o STM de Clojure neste vídeo


3

Linguagens funcionais, por definição, não devem manter variáveis ​​de estado

Sua definição está errada. Linguagem que não pode manter o estado simplesmente não pode ser usada.

A diferença entre linguagens funcionais e imperativas não é que uma delas tenha estado e a outra não. É de certa forma que eles mantêm o estado.

Linguagens imperativas têm estado espalhado por todo o programa.

Linguagens funcionais isolam e mantêm o estado explicitamente por meio de assinaturas de tipo. E é por isso que eles fornecem mecanismos sofisticados de gerenciamento de estado, como o STM.


2

Às vezes, um programa requer um estado mutável (por exemplo, conteúdo de banco de dados para um aplicativo Web) e seria ótimo poder usá-lo sem perder os benefícios da programação funcional. Em linguagens não funcionais, o estado mutável permeia tudo. Se você o tornar explícito com algum tipo de API especial , poderá confiná-lo a uma pequena região identificável, enquanto todo o resto permanecerá puramente funcional. Os benefícios do FP incluem depuração mais fácil, teste de unidade repetível, simultaneidade indolor e compatibilidade com vários núcleos / GPU.


Você provavelmente quer dizer estado mutável. Todos os programas mantêm estado, mesmo os funcionais.
Robert Harvey

Você está certo. Claramente, não estou gastando tempo suficiente fazendo programação funcional, para ter perdido isso.
Will Ware
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.