Können wir alles in imperativen Sprachen mit einer funktionalen Sprache tun, wenn dies keinen „Zustand“ zulässt?

7

Ich las Struktur und Interpretation von Computerprogrammen (SICP), MIT. Was ich verstanden habe ist, dass es in einer rein funktionalen Programmiersprache keinen lokalen Staat gibt. SICP, S. 230 sagt:

"Das Programmieren ohne Verwendung von Aufgaben, wie wir es in den letzten beiden Kapiteln dieses Buches getan haben, wird dementsprechend als funktionale Programmierung bezeichnet."

Ich komme aus einem zwingenden Programmierhintergrund und kann anscheinend nicht verstehen, wie man ein Programm entwirft, das ein reales System (wie eine einfache Bank oder eine Bibliotheksverwaltungssoftware) ohne die Idee eines Staates modelliert.

Wie machen wir das, wenn die funktionale Programmierung nicht die Idee eines Zustands hat?

daltonfury42
quelle

Antworten:

8

Der Schlüssel bei der funktionalen Programmierung ist nicht, dass es keinen Status gibt, sondern dass es einen expliziten Status gibt .

Dies bedeutet, dass Ihr Status als Parameter an Ihre Funktionen weitergegeben wird. Es ist ein tatsächlicher Wert, den Sie in die Hände bekommen, betrachten und an andere Funktionen weitergeben können.

Schauen wir uns zum Beispiel die dynamische Programmiermethode zur Berechnung der Fibonacci-Zahlen an. In einer imperativen Sprache hätten Sie so etwas:

def fib(n):
  A = {}
  A[0] = 0
  A[1] = 1
  for i in [2 .. n+1]:
      A[i] = A[i-1] + A[i-2]
  return A[n]

Um dies ohne Status zu tun, müssen Sie Ihren Shop nur explizit weitergeben. Verwenden der Haskell-ish-Syntax:

fib n = fibHelper 2 n {(1,1), (0,0)}

fibHelper i end cache = 
  if 
    i > end
  then 
    lookup end cache
  else
    let
      newVal = (lookup (i-1) cache) + (lookup (i-2) cache)
      newCache = insert i newVal cache
    in
      fibHelper (i+1) end newCache

Dies ist etwas kompliziert, da Sie nicht das gesamte Array für die Fibonacci-Zahlen benötigen, aber Sie können sich vorstellen, dies für kompliziertere dynamische Programmierprobleme wie Knapsack zu verwenden, bei denen Sie den gesamten Satz zuvor berechneter Werte benötigen.

Das Wichtigste dabei ist, dass insertes sich um eine Funktion handelt, die ein Geschäft übernimmt und ein neues Geschäft zurückgibt, das dem Original mit einem neuen Mehrwert entspricht. Der ursprüngliche Wert von cachewird nicht zerstört. Wenn Sie also eine Anwendung hatten, in der Sie eine Art "Rückgängig" -Operation benötigten, können Sie den Verlauf Ihres Staates verfolgen.

Sie könnten sagen "aber das sieht ineffizient aus! Sie erstellen jedes Mal ein ganz neues Geschäft!" In der Regel werden diese Dinge jedoch in funktionalen Sprachen mithilfe von Referenzen geschickt implementiert, sodass keine ganz neuen Kopien der Daten herumliegen.

Es ist auch erwähnenswert, dass dieses Muster, einen Statusparameter zu haben, ihn im Verlauf Ihrer Berechnung weiterzugeben und zu ändern, sehr häufig ist. Menschen haben Abstraktionen erfunden, wie die Staatsmonade , mit denen Sie Dinge schreiben können, die zwingend aussehen, die aber "unter der Haube" rein funktional sind.

jmite
quelle