Gibt es eine Möglichkeit, GHC zu zwingen, eine bestimmte Berechnung für die Lebensdauer eines bestimmten Werts zu treffen?Gibt es eine implizite ish-Memoisierung in Haskell?
Ich könnte offensichtlich den Wert in einen Datensatz legen, Lazy Record-Einträge für das Ergebnis der Berechnung erstellen, und erstellen Sie eine Maker-Funktion, die den Datensatz erstellt und den Wert in die Einträge thunks.
Ich würde es hassen, den ursprünglichen Wert aus der Aufzeichnung jedes Mal ziehen, wenn ich es wollte. Und Haskell hat keine ad hoc polymorphen Is-A-Beziehungen wie C++ oder Java.
Gibt es einen Trick für das Memo von Werten über mehrere unabhängige Aufrufe einer Funktion mit identischen Parametern?
Ich konnte mir vage verschiedene Tricks mit Formen von abhängigen Typen vorstellen, die dem Compiler mehrere Nutzungen mitteilen würden. Es gibt keine abhängigen Typen in Haskell, aber vielleicht etwas um implizite Parameter? Ich vermute nicht, aber ich dachte, ich würde fragen. Ein Pragma vielleicht?
Imagine ich einen Vektor von Necklace
Datenstrukturen haben, für die ich einen resultierenden Vektor der rationalen Zahlen benötigen, als gemeinsamen Nenner und einen Vektor von Zählern gespeichert.
{-# LANGUAGE ImplicitParams #-}
import qualified Data.Vector as V
data Necklace = Necklace { ... }
necklace_length n = ...
denominator :: (necklaces :: V.Vector Necklace) => Int
denominator = V.foldl' lcm 30 $ V.map necklace_length ?necklaces
numerators :: (necklaces :: V.Vector Necklace) => V.Vector Int
numerators = V.map f ?necklaces
where f x = ... denominator ...
kittytoy :: (necklaces :: V.Vector Necklace) => Meow -> ...
kittytoy = \meow -> ... numerators ...
A priori, ich erwarten würde, wenn ich kittytoy
mehrere Millionen Mal aufrufen, die jeweils mit einem anderen Parameter meow
, dann erzeugt GHC-Code, der numerators
eine Million Mal, jeweils mit einer identischen impliziten Parameter necklaces
aufruft.
Es ist dennoch offensichtlich, dass numerators
nur einmal aufgerufen werden muss, das erste mal ?necklaces
zugewiesen wird, was bedeutet, dass GHC möglicherweise diese Optimierung bemerken könnte.
Es sollte sogar einen expliziten Code-Refactoring-Ansatz geben, der Vorlagenhaskell verwendet, um die Thunks explizit zu übergeben, indem Code wie ?numerators = numerators
erzeugt und numerators :: V.Vector Int
hinzugefügt wird, um Einschränkungen von Funktionen einzugeben, die ihn aufrufen.
'kittytoy halsketten = lassen n = zähler halsketten in \ meow -> stuff 'sollte auf jeden fall memoize' n'. Nicht sicher, ob es auch so ist wie es ist. – yairchu
Meinst du 'let k = kittytoy in ...' ersetzt jeden Anruf zu 'kittytoy' mit' k'? Ja, ich stimme zu, dass ich den impliziten Parameter "Halsketten" notieren sollte, aber sollte ich das wirklich tun müssen? –
Ahh, nein, ich versuche, 'Zähler' * außerhalb * des Aufrufs von' kittytoy' zu merken, weil 'kittytoy' selbst mehrere Millionen Male aufgerufen wird. Ja, das ist ein gültiger Punkt, dass 'kittytoy' unabhängig davon ein Lambda-Ausdruck sein sollte, ich werde es aus Gründen der Klarheit bearbeiten. –