Pourquoi certains langages fonctionnels ont-ils besoin de mémoire transactionnelle logicielle?

24

Les langages fonctionnels, par définition, ne devraient pas conserver de variables d'état. Pourquoi, alors, Haskell, Clojure et d'autres fournissent-ils des implémentations logicielles de mémoire transactionnelle (STM)? Y a-t-il un conflit entre deux approches?

Michael Spector
la source
Je voudrais simplement relier cet article intéressant qui explique beaucoup de choses.
Falcon
1
Pour être clair, tous les langages fonctionnels conservent leur état, mais la pureté dicte que la valeur d'une variable ne change pas une fois qu'elle est définie.
Robert Harvey

Réponses:

13

Il n'y a rien de mal à ce qu'un langage fonctionnel maintienne un état mutable. Même les langages fonctionnels "purs" tels que Haskell doivent maintenir leur état pour interagir avec le monde réel. Les langages fonctionnels "impurs" comme Clojure permettent des effets secondaires qui peuvent inclure l'état de mutation.

Le point principal est que les langages fonctionnels découragent l'état mutable, sauf si vous en avez vraiment besoin . Le style général est de programmer en utilisant des fonctions pures et des données immuables, et d'interagir uniquement avec l'état mutable "impur" dans les parties spécifiques de votre code qui en ont besoin. De cette façon, vous pouvez garder le reste de votre base de code "pur".

Je pense qu'il y a plusieurs raisons pour lesquelles la STM est plus courante dans les langages fonctionnels:

  • Recherche : la STM est un sujet de recherche brûlant, et les chercheurs en langage de programmation préfèrent souvent travailler avec des langages fonctionnels (un sujet de recherche en soi, plus il est plus facile de créer des "preuves" sur le comportement du programme)
  • Le verrouillage ne compose pas : STM peut être considéré comme une alternative aux approches de concurrence basées sur le verrouillage, qui commencent à rencontrer des problèmes lorsque vous évoluez vers des systèmes complexes en composant différents composants. C'est sans doute la principale raison "pragmatique" de la STM
  • STM correspond bien à l'immuabilité : si vous avez une grande structure immuable, vous voulez vous assurer qu'elle reste immuable, donc vous ne voulez pas qu'un autre thread entre et mute un sous-élément. De même, si vous pouvez garantir l'immuabilité de ladite structure de données, vous pouvez considérer de manière fiable qu'il s'agit d'une "valeur" stable dans votre système STM.

Personnellement, j'aime l'approche de Clojure consistant à autoriser la mutabilité, mais uniquement dans le contexte de «références gérées» strictement contrôlées qui peuvent participer aux transactions STM. Tout le reste dans la langue est "purement fonctionnel".

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

Notez que le code ci-dessus est entièrement transactionnel et atomique - un observateur externe lisant les deux soldes dans une autre transaction verra toujours un état atomique cohérent, c'est-à-dire que les deux soldes totaliseront toujours 200. Avec la concurrence basée sur les verrous, c'est un problème étonnamment difficile à résoudre dans un grand système complexe avec de nombreuses entités transactionnelles.

Pour un éclaircissement supplémentaire, Rich Hickey fait un excellent travail pour expliquer la STM de Clojure dans cette vidéo

mikera
la source
3

Les langages fonctionnels, par définition, ne devraient pas conserver de variables d'état

Votre définition est fausse. Un langage qui ne peut pas maintenir l'état ne peut tout simplement pas être utilisé.

La différence entre les langages fonctionnels et impératifs n'est pas que l'un d'eux a un état et l'autre pas. C'est en quelque sorte qu'ils maintiennent l'État.

Les langues impératives se sont répandues dans tout le programme.

Les langages fonctionnels isolent et maintiennent l'état explicitement via des signatures de type. Et c'est la raison pour laquelle ils fournissent des mécanismes de gestion d'état sophistiqués comme STM.

Vagif Verdi
la source
2

Parfois, un programme nécessite un état mutable (par exemple, le contenu d'une base de données pour une application Web) et il serait formidable de pouvoir l'utiliser sans perdre les avantages de la programmation fonctionnelle. Dans les langages non fonctionnels, l'état mutable imprègne tout. Si vous le rendez explicite avec une sorte d' API spéciale , vous pouvez le limiter à une petite région identifiable tandis que tout le reste reste purement fonctionnel. Les avantages de FP incluent un débogage plus facile, des tests unitaires reproductibles, une concurrence simultanée indolore et une convivialité multicœur / GPU.

Will Ware
la source
Vous voulez probablement dire un état mutable. Tous les programmes conservent leur état, même les plus fonctionnels.
Robert Harvey
Tu as raison. Clairement, je ne passe pas assez de temps à faire de la programmation fonctionnelle, pour l'avoir manqué.
Will Ware