Prelude Exponentiation ist schwer zu verstehen

7

Ich las das Haskell-Prelude und fand es ziemlich verständlich, dann stolperte ich über die Definition der Exponentiation:

%Vor%

Ich verstehe die Notwendigkeit von zwei verschachtelten where s nicht.

Was ich bisher verstanden habe:

%Vor%

Die Basis muss eine Zahl sein und der Exponent intege, ok.

%Vor%

Basisfall, einfach.

%Vor%

Exponention durch Quadrieren ... Art von ... Warum wird der f Helfer benötigt? Warum sind f und g mit einem Buchstaben versehen? Ist es nur Optimierung, vermisse ich etwas Offensichtliches?

%Vor%

N & gt; 0 wurde vorher überprüft, N ist negativ, wenn wir hier ankommen, also Fehler.

Meine Implementierung wäre eine direkte Übersetzung von:

%Vor%

Pseudocode aus Wikipedia.

    
Caridorc 28.08.2015, 12:17
quelle

4 Antworten

12

Um zu verdeutlichen, was @dfeuer sagt, beachte, dass die Art f es entweder geschrieben hat:

  1. f gibt einen Wert
  2. zurück
  3. oder, f ruft sich selbst mit neuen Argumenten
  4. auf

Daher ist f tail rekursiv und kann daher leicht in eine Schleife umgewandelt werden.

Betrachten Sie andererseits diese alternative Implementierung der Potenzierung durch Quadrieren:

%Vor%

Das Problem hierbei ist, dass in der anderen Klausel die letzte durchgeführte Operation eine Multiplikation ist. Also exp entweder:

  1. gibt 1
  2. zurück
  3. nennt sich selbst mit neuen Argumenten
  4. ruft sich selbst mit einigen neuen Argumenten auf und multipliziert das Ergebnis mit x .

exp ist nicht tail rekursiv und kann daher nicht in eine Schleife umgewandelt werden.

    
ErikR 28.08.2015, 13:01
quelle
7

f ist in der Tat eine Optimierung. Der naive Ansatz wäre "von oben nach unten", berechnet x^(n 'div' 2) und quadriert dann das Ergebnis. Der Nachteil dieses Ansatzes besteht darin, dass er einen Stapel von Zwischenberechnungen aufbaut. Was f diese Implementierung tun lässt, ist das erste Quadrat x (eine einzelne Multiplikation) und hebt dann das Ergebnis auf den reduzierten Exponenten, Tail rekursiv, an. Das Endergebnis ist, dass die Funktion wahrscheinlich vollständig in Maschinenregistern arbeitet. g scheint zu vermeiden, das Ende der Schleife zu prüfen, wenn der Exponent gerade ist, aber ich bin mir nicht sicher, ob es eine gute Idee ist.

    
dfeuer 28.08.2015 12:48
quelle
1

Soweit ich es verstehe, wird die Potenzierung durch Quadrieren gelöst, solange der Exponent gerade ist.

Dies führt zu der Antwort, warum f im Falle einer ungeraden Zahl benötigt wird - wir verwenden f , um das Ergebnis im Fall von g x 1 zurückzugeben, in jedem anderen ungeraden Fall verwenden wir f zurück in der g -Routine.

Sie können es am besten sehen, wenn Sie sich ein Beispiel ansehen:

%Vor%

Nun zu Ihrer Frage, einzelne Buchstabenfunktionsnamen zu verwenden - daran müssen Sie sich erst gewöhnen, schreiben die meisten Leute in der Community. Es hat keine Auswirkungen auf den Compiler, wie Sie Ihre Funktionen benennen - solange sie mit einem Kleinbuchstaben beginnen.

    
epsilonhalbe 28.08.2015 12:51
quelle
1

Wie bereits erwähnt, wird die Funktion aus Effizienzgründen mit Tail-Recursion geschrieben.

Beachten Sie jedoch, dass Sie das innerste where entfernen können, während Sie die Schwanzrekursion wie folgt beibehalten: statt

%Vor%

können wir verwenden

%Vor%

was auch besser lesbar ist.

Ich habe jedoch keine Ahnung, warum die Autoren des Preludes ihre Variante gewählt haben.

    
chi 28.08.2015 15:33
quelle