Bei der Erforschung von Memoization in Scala habe ich Code gefunden, den ich nicht gekriegt habe. Ich habe versucht, dieses spezielle "Ding" zu sehen, weiß aber nicht, wie ich es nennen soll; d.h. der Begriff, auf den Bezug genommen werden soll. Außerdem ist es nicht einfach, mit einem Symbol zu suchen, äh!
Ich habe den folgenden Code gesehen, um in Scala hier zu memozieren :
%Vor% Und es ist, was die Fallklasse ausdehnt, die mich verwirrt, den extends (A => B)
-Teil. Erstens, was passiert? Zweitens, warum wird es überhaupt benötigt? Und schließlich, wie nennt man diese Art von Erbschaft? d. h. Gibt es einen bestimmten Namen oder Begriff, mit dem ich mich darauf beziehen kann?
Als nächstes sehe ich, wie Memo auf diese Weise eine Fibanocci-Nummer berechnet: hier :
%Vor% Es ist wahrscheinlich, dass ich nicht alle "Vereinfachungen" sehe, die angewendet werden. Aber ich bin nicht in der Lage, das Ende der val
-Zeile, = Memo {
, herauszufinden. Also, wenn dies ausführlicher getippt würde, würde ich vielleicht den "Sprung" verstehen, der gemacht wird, wie das Memo konstruiert wird.
Jede Unterstützung wird sehr geschätzt. Danke.
Diese Antwort ist eine Synthese der Teilantworten von 0__ und Nicolas Rinaudo.
Zusammenfassung:
Es gibt viele praktische (aber auch stark verflochtene) Annahmen, die der Scala-Compiler trifft.
extends (A => B)
synonym mit extends Function1[A, B]
( ScalaDoc für Funktion1 [+ T1, -R] ) apply(x: A): B
von Function1 muss bereitgestellt werden; %Code%
def apply(x: A): B = cache.getOrElseUpdate(x, f(x))
für den Codeblock aus, der mit match
beginnt.
= Memo {
, der in Element 3 gestartet wurde, als Parameter an den Memo-Fallklassenkonstruktor {}
in Element 3 als {}
an und der Compiler verwendet den Codeblock "match" als Überschreibung für das PartialFunction[Int, BigInt]
der PartialFunction-Methode und bietet dann eine zusätzliche Überschreibung für die Methode der PartialFunction %Code%. Details:
Der erste Codeblock, der die Fallklasse Memo definiert, kann ausführlicher geschrieben werden:
%Vor%Der zweite Codeblock, der den Wert fibanocci definiert, kann ausführlicher als solcher geschrieben werden:
%Vor% Er musste apply()
zum Wert des zweiten Codeblocks hinzufügen, um mit einem selbstreferentiellen Problem in der Zeile isDefinedAt()
fertig zu werden.
Und schließlich ist eine Beispielverwendung von Fibonacci:
%Vor% A => B
ist die Abkürzung für Function1[A, B]
, also erweitert Memo
eine Funktion von A
auf B
, am deutlichsten durch die Methode apply(x: A): B
definiert, die definiert werden muss.
Wegen der "Infix" -Notation müssen Sie Klammern um den Typ setzen, d. h. (A => B)
. Du könntest auch schreiben
oder
%Vor% Um die Antwort von 0_ zu vervollständigen, wird fibonacci
über die Methode apply des Companion-Objekts Memo
erstellt, das automatisch vom Compiler generiert wird, da Memo
eine Case-Klasse ist.
Dies bedeutet, dass der folgende Code für Sie generiert wird:
%Vor% Scala hat eine spezielle Behandlung für die Methode apply
: Der Name muss beim Aufruf nicht eingegeben werden. Die beiden folgenden Aufrufe sind genau gleich:
Der case
-Block ist als Mustervergleich bekannt. Unter der Haube erzeugt es eine Teilfunktion, dh eine Funktion, die für einige ihrer Eingabeparameter definiert ist, aber nicht notwendigerweise für alle von ihnen. Ich werde nicht in die Details von Teilfunktionen gehen, da es neben dem Punkt ist ( dies ist ein Memo, das ich mir zu diesem Thema geschrieben habe, wenn Sie daran interessiert sind), aber was es hier im Wesentlichen bedeutet, ist, dass der Block case
tatsächlich eine Instanz von PartialFunction .
Wenn Sie diesem Link folgen, sehen Sie, dass PartialFunction
sich erweitert Function1 - das ist das erwartete Argument von Memo.apply
.
Also, was dieses Bit Code eigentlich bedeutet, einmal entzuckert (wenn das ein Wort ist), ist:
%Vor% Beachten Sie, dass ich die Handhabung des Mustervergleichs erheblich vereinfacht habe, aber ich dachte, dass das Starten einer Diskussion über unapply
und unapplySeq
off-topic und verwirrend wäre.
Noch ein Wort zu diesem extends (A => B)
: Das extends
hier ist nicht erforderlich, aber notwendig, wenn die Instanzen von Memo
in Funktionen oder Situationen höherer Ordnung verwendet werden sollen.
Ohne diese extends (A => B)
ist es völlig in Ordnung, wenn Sie die Memo
instance fibonacci
nur in Methodenaufrufen verwenden.
Zum Beispiel:
%Vor%Aber wenn Sie es in Funktionen höherer Ordnung verwenden möchten, haben Sie einen Typenkonfliktfehler.
%Vor% Also hilft das extends
hier nur, die Instanz fibonacci
für andere zu identifizieren, dass es eine apply
-Methode hat und somit einige Jobs erledigen kann.
Tags und Links scala map memoization