Perché alcuni linguaggi funzionali necessitano di 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 software (STM)? C'è un conflitto tra due approcci?

    
posta spektom 07.09.2011 - 15:42
fonte

3 risposte

12

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

Il punto principale è che le lingue funzionali scoraggiano lo stato mutabile a meno che non ne abbia davvero bisogno . Lo stile generale è quello di 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 il resto della tua base di codice "puro".

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

  • Ricerca : STM è un argomento di ricerca molto diffuso e i ricercatori di linguaggi di programmazione preferiscono spesso lavorare con linguaggi funzionali (un argomento di ricerca in sé, inoltre è più facile creare "prove" sul comportamento del programma)
  • Lock non compose : STM può essere visto come un'alternativa agli approcci basati su lock alla concorrenza, che inizia a incorrere in problemi quando si passa a sistemi complessi componendo componenti diversi. Questo è probabilmente il principale motivo "pragmatico" per STM
  • STM si adatta bene con l'immutabilità : se hai una grande struttura immutabile, vuoi assicurarti che rimanga immutabile, così non vuoi che qualche altro thread entri e muti qualche elemento secondario. Allo stesso modo, se è possibile garantire l'immutabilità di detta struttura dati, è possibile trattare in modo affidabile come "valore" stabile nel sistema STM.

Personalmente mi piace l'approccio di Clojure che consente la mutabilità, ma solo nel contesto di "riferimenti gestiti" strettamente 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

Nota che il codice precedente è completamente transazionale e atomico: un osservatore esterno che legge i due saldi di un'altra transazione vedrà sempre uno stato atomico coerente, cioè i due saldi saranno sempre pari a 200. Con la concorrenza basata sui blocchi, questo è un sorprendentemente difficile da risolvere in un sistema complesso con molte entità transazionali.

Per alcuni chiarimenti extra, Rich Hickey fa un eccellente lavoro di spiegazione dello STM di Clojure in questo video

    
risposta data 25.09.2011 - 05:38
fonte
3

Functional languages, by definition, should not maintain state variables

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

La differenza tra linguaggi funzionali e imperativi non è che uno di essi abbia uno stato e l'altro no. È in un modo che mantengono lo stato.

Le lingue imperative si sono diffuse in tutto il programma.

Le lingue funzionali isolano e mantengono lo stato esplicitamente tramite le firme dei tipi. E questo è il motivo per cui forniscono meccanismi sofisticati di gestione dello stato come STM.

    
risposta data 09.09.2011 - 22:23
fonte
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 benefits di programmazione funzionale. Nei linguaggi non funzionali, lo stato mutabile permea tutto. Se lo rendi esplicito con qualche tipo di API speciale , puoi limitarlo a una piccola area identificabile mentre tutto altro rimane puramente funzionale. I vantaggi di FP comprendono un debugging più semplice, test unitari ripetibili, concorrenza indolore e cordialità multicore / GPU.

    
risposta data 07.09.2011 - 17:40
fonte

Leggi altre domande sui tag