Perché alcuni linguaggi funzionali richiedono memoria transazionale del software?


24

I linguaggi funzionali, per definizione, non dovrebbero mantenere variabili di stato. Perché, allora, Haskell, Clojure e altri forniscono implementazioni di memoria transazionale di software (STM)? Esiste un conflitto tra due approcci?


Vorrei solo collegare questo interessante documento che spiega parecchio.
Falcon,

1
Per essere chiari, tutti i linguaggi funzionali mantengono lo stato, ma la purezza impone che il valore di una variabile non cambi una volta impostato.
Robert Harvey,

Risposte:


13

Non c'è nulla di sbagliato in un linguaggio funzionale che mantiene lo stato mutevole. Anche i linguaggi funzionali "puri" come Haskell devono mantenere lo stato per interagire con il mondo reale. Linguaggi funzionali "impuri" come Clojure consentono effetti collaterali che possono includere lo stato mutante.

Il punto principale è che i linguaggi funzionali scoraggiano lo stato mutabile meno che non ne abbia davvero bisogno . Lo stile generale è programmare utilizzando funzioni pure e dati immutabili e interagire solo con lo stato mutabile "impuro" nelle parti specifiche del codice che lo richiedono. In questo modo, puoi mantenere "puro" il resto della tua base di codice.

Penso che ci siano diversi motivi per cui STM è più comune nei linguaggi funzionali:

  • Ricerca : la STM è un argomento di ricerca molto richiesto e i ricercatori del linguaggio di programmazione preferiscono spesso lavorare con linguaggi funzionali (un argomento di ricerca in sé, inoltre è più facile creare "prove" sul comportamento del programma)
  • Il blocco non si compone : STM può essere visto come un'alternativa agli approcci alla concorrenza basati sul blocco, che inizia a incorrere in problemi quando si passa a sistemi complessi componendo componenti diversi. Questo è probabilmente il motivo "pragmatico" principale per STM
  • STM si adatta bene all'immutabilità : se hai una grande struttura immutabile, vuoi assicurarti che rimanga immutabile, quindi non vuoi che altri thread entrino e muthino alcuni sotto-elementi. Allo stesso modo, se si può garantire l'immutabilità di detta struttura di dati, è possibile considerare in modo affidabile un "valore" stabile nel proprio sistema STM.

Personalmente mi piace l'approccio di Clojure di consentire la mutabilità, ma solo nel contesto di "riferimenti gestiti" rigorosamente controllati che possono partecipare alle transazioni STM. Tutto il resto nella lingua è "puramente funzionale".

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

Si noti che il codice sopra è completamente transazionale e atomico: un osservatore esterno che legge i due saldi all'interno di un'altra transazione vedrà sempre uno stato atomico coerente, ovvero i due saldi saranno sempre pari a 200. Con la concorrenza basata su blocco, questo è un problema sorprendentemente difficile risolvere in un grande sistema complesso con molte entità transazionali.

Per un po 'di illuminazione in più, Rich Hickey fa un ottimo lavoro nel spiegare l'STM di Clojure in questo video


3

I linguaggi funzionali, per definizione, non dovrebbero mantenere variabili di stato

La tua definizione è sbagliata. La lingua che non può mantenere lo stato semplicemente non può essere utilizzata.

La differenza tra i linguaggi funzionali e quelli imperativi non è che uno di essi ha uno stato e l'altro no. In un certo senso mantengono lo stato.

Le lingue imperative sono state diffuse dallo stato in tutto il programma.

I linguaggi funzionali isolano e mantengono esplicitamente lo stato tramite firme di tipo. Ed è per questo che forniscono sofisticati meccanismi di gestione dello stato come STM.


2

A volte un programma richiede uno stato mutabile (ad esempio, i contenuti del database per un'app Web) e sarebbe bello poterlo utilizzare senza perdere i vantaggi della programmazione funzionale. Nei linguaggi non funzionali, lo stato mutevole permea tutto. Se lo rendi esplicito con un qualche tipo di API speciale , puoi limitarlo a una piccola regione identificabile mentre tutto il resto rimane puramente funzionale. I vantaggi di FP includono un debug più semplice, test unitari ripetibili, concorrenza indolore e compatibilità multicore / GPU.


Probabilmente intendi lo stato mutabile. Tutti i programmi mantengono lo stato, anche quelli funzionali.
Robert Harvey,

Hai ragione. Chiaramente non sto trascorrendo abbastanza tempo a fare la programmazione funzionale, per essermelo perso.
Ware il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.