Es ist durchaus möglich, dass um zu wissen, ob eine Funktion zu irgendeinem Zeitpunkt definiert ist, ein wesentlicher Teil der Berechnung ihres Werts durchgeführt werden muss. In einem PartialFunction
müssen beide Methoden bei der Implementierung von isDefined
und apply
dies tun. Was ist zu tun, ist diese gemeinsame Arbeit teuer?
Es gibt die Möglichkeit, sein Ergebnis zwischenzuspeichern, in der Hoffnung, dass apply nach isDefined aufgerufen wird. Definitiv hässlich.
Ich wünsche mir oft, dass PartialFunction[A,B]
Function[A, Option[B]]
wäre, was eindeutig isomorph ist. Oder vielleicht könnte es eine andere Methode in PartialFunction
geben, sagen wir applyOption(a: A): Option[B]
. Bei einigen Mixins hätten Implementierer die Wahl, entweder isDefined und apply oder applyOption zu implementieren. Oder alle auf der sicheren Seite, leistungsorientiert. Clients, die isDefined
vor dem Aufruf von apply testen, sollten stattdessen applyOption
verwenden.
Das ist jedoch nicht so. Einige der wichtigsten Methoden in der Bibliothek, darunter collect
in Sammlungen, benötigen ein PartialFunction
. Gibt es einen sauberen (oder nicht so sauberen) Weg, um Berechnungen zu vermeiden, die zwischen isDefined und apply wiederholt werden?
Ist die Methode applyOption(a: A): Option[B]
auch sinnvoll? Klingt es machbar, es in einer zukünftigen Version hinzuzufügen? Wäre es das wert?
Warum ist Caching so ein Problem? In den meisten Fällen haben Sie eine lokale Berechnung. Wenn Sie also einen Wrapper für das Caching schreiben, müssen Sie sich keine Gedanken darüber machen. Ich habe den folgenden Code in meiner Dienstprogrammbibliothek:
%Vor% und dann, wenn ich eine teure Berechnung habe, schreibe ich eine Funktionsmethode A => Option[B]
und mache etwas wie (f _).drop
, um es in collect oder whatnot zu verwenden. (Wenn Sie es inline machen wollten, könnten Sie eine Methode erstellen, die A=>Option[B]
übernimmt und eine Teilfunktion zurückgibt.)
(Die umgekehrte Transformation - von PartialFunction
nach A => Option[B]
- heißt Heben, daher ist der "Tropfen"; ich glaube, ein "unlift" ist ein weit verbreiteter Begriff für die entgegengesetzte Operation.) p>
Schauen Sie sich diesen Thread an, Teilfunktion neu denken . Du bist nicht der Einzige, der sich darüber Gedanken macht.
Das ist eine interessante Frage, und ich gebe meine 2 Cent.
Erstens widerstehen Sie dem Drang nach voreiliger Optimierung. Stellen Sie sicher, dass die Teilfunktion das Problem ist. Ich war erstaunt, wie schnell sie in einigen Fällen sind.
Nun angenommen, es gibt ein Problem, wo käme es her?
Eine Option Ich würde versuchen, Wege zu finden, schnell zu versagen. Brechen Sie die Mustererkennung in die Ebene und verketten Sie dann Teilfunktionen. Auf diese Weise können Sie das Spiel vorzeitig beenden. Extrahieren Sie auch wiederholtes Sub-Matching. Zum Beispiel:
Nehmen wir an, OddEvenList ist ein Extraktor, der eine Liste in eine ungerade Liste und eine gerade Liste aufteilt:
%Vor%Brechen Sie in zwei Teile, einen Teil, der mit dem Teilungswert übereinstimmt, und einen Teil, der versucht, mit dem Ergebnis übereinzustimmen (um wiederholte Berechnungen zu vermeiden. Dies erfordert jedoch ein gewisses Reengineering.
%Vor%Ich habe dies beim progressiven Lesen von XML-Dateien verwendet, die ein ziemlich unbeständiges Format haben.
Eine weitere Möglichkeit besteht darin, Teilfunktionen mit andThen
zu erstellen. Obwohl hier ein schneller Test gezeigt wurde, um anzuzeigen, dass nur der erste Test tatsächlich getestet wurde.
Es ist absolut nichts falsch mit Caching-Mechanismus innerhalb der Teilfunktion, wenn:
Eine solche zwischengespeicherte Funktion kann nicht von einer einfachen alten reinen Partialfunktion unterschieden werden ...
Tags und Links scala