Funktionssprachen sollten per Definition keine Statusvariablen verwalten. Warum bieten dann Haskell, Clojure und andere Implementierungen von Software Transactional Memory (STM) an? Gibt es einen Konflikt zwischen zwei Ansätzen?
Funktionssprachen sollten per Definition keine Statusvariablen verwalten. Warum bieten dann Haskell, Clojure und andere Implementierungen von Software Transactional Memory (STM) an? Gibt es einen Konflikt zwischen zwei Ansätzen?
Antworten:
An einer funktionalen Sprache, die einen veränderlichen Zustand beibehält, ist nichts auszusetzen. Sogar "reine" funktionale Sprachen wie Haskell müssen den Zustand aufrechterhalten, um mit der realen Welt interagieren zu können. "Unreine" Funktionssprachen wie Clojure ermöglichen Nebenwirkungen, die Mutationen einschließen können.
Der wichtigste Punkt ist, dass funktionale Sprachen den veränderlichen Zustand verhindern, es sei denn, Sie brauchen ihn wirklich . Der allgemeine Stil besteht darin, mit reinen Funktionen und unveränderlichen Daten zu programmieren und nur mit "unreinen" veränderlichen Zuständen in den spezifischen Teilen Ihres Codes zu interagieren, die dies erfordern. Auf diese Weise können Sie den Rest Ihrer Codebasis "rein" halten.
Ich denke, es gibt mehrere Gründe, warum STM in funktionalen Sprachen häufiger vorkommt:
Ich persönlich mag Clojures Ansatz, die Veränderbarkeit zuzulassen, aber nur im Kontext streng kontrollierter "verwalteter Referenzen", die an STM-Transaktionen teilnehmen können. Alles andere in der Sprache ist "rein funktional".
;; 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
Beachten Sie, dass der obige Code vollständig transaktionell und atomar ist - ein externer Beobachter, der die beiden Salden innerhalb einer anderen Transaktion liest, sieht immer einen konsistenten atomaren Zustand, dh die beiden Salden summieren sich immer auf 200. Bei einer sperrenbasierten Parallelität ist dies ein überraschend schwieriges Problem in einem großen komplexen System mit vielen Transaktionsentitäten zu lösen.
Für zusätzliche Aufklärung leistet Rich Hickey in diesem Video eine hervorragende Erklärung für Clojures STM
Funktionssprachen sollten per Definition keine Statusvariablen verwalten
Deine Definition ist falsch. Sprache, die den Status nicht aufrechterhalten kann, kann einfach nicht verwendet werden.
Der Unterschied zwischen funktionalen und imperativen Sprachen besteht nicht darin, dass eine von ihnen einen Staat hat und die andere nicht. Es ist in gewisser Weise, dass sie den Staat aufrechterhalten.
Imperative Sprachen haben Staat im ganzen Programm verbreitet.
Funktionssprachen isolieren und pflegen den Zustand explizit über Typensignaturen. Und das ist der Grund, warum sie ausgefeilte Zustandsverwaltungsmechanismen wie STM bereitstellen.
Manchmal erfordert ein Programm einen veränderlichen Status (z. B. Datenbankinhalte für eine Web-App), und es wäre großartig, wenn Sie es verwenden könnten, ohne die Vorteile der funktionalen Programmierung zu verlieren . In nicht funktionalen Sprachen durchdringt der veränderbare Zustand alles. Wenn Sie es mit einer speziellen API explizit machen , können Sie es auf einen kleinen identifizierbaren Bereich beschränken, während alles andere rein funktional bleibt. Zu den Vorteilen von FP zählen ein einfacheres Debugging, wiederholbare Komponententests, eine reibungslose Parallelität und die Benutzerfreundlichkeit von Multicore / GPU.