Haskell dreht sich alles um Abstraktion. Aber Abstraktion kostet uns zusätzliche CPU-Zyklen und zusätzlichen Speicherverbrauch aufgrund der gemeinsamen Darstellung aller abstrakten (polymorphen) Daten - Zeiger auf Heap. Es gibt einige Möglichkeiten, um abstrakten Code mit hohen Leistungsanforderungen besser zu spielen. Soweit ich es verstehe, ist eine Art, es zu tun, Spezialisierung - im Grunde extra Code-Generierung (manuell oder durch Compiler), richtig?Haskell (GHC) Spezialtour & effiziente TypFamilien
Nehmen wir an, dass der gesamte Code unten ist Strict
Wenn wir eine Funktion sum
haben (der Compiler mehr Optimierungen durchführen hilft?):
sum :: (Num a) => a -> a -> a
Wir spezialisierte Version davon specialize
mit erzeugen kann pragma:
{-#SPECIALIZE sum :: Float -> Float -> Float#-}
Jetzt, wenn Haskell Compiler kann Bestimmen Sie zur Kompilierzeit, dass wir sum
auf zwei Float
s aufrufen, es wird spezialisierte Version davon verwenden. Keine Heap-Allokationen, oder?
Funktionen - fertig. Dasselbe Pragma kann auf Klasseninstanzen angewendet werden. Logik ändert sich hier nicht, oder?
Aber was ist mit Datentypen? Ich vermute, dass TypeFamilies
hier zuständig sind?
Lassen Sie uns versuchen, abhängige längenindexierte Liste zu spezialisieren.
--UVec for unboxed vector
class UVec a where
data Vec (n :: Nat) a :: *
instance UVec Float where
data Vec n Float where
VNilFloat :: Vec 0 Float
VConsFloat :: {-#UNPACK#-}Float ->
Vec n Float ->
Vec (N :+ 1) Float
Aber Vec
hat ein Problem. Wir können keine Mustervergleiche für seine Konstruktoren erstellen, da jede Instanz von UVec
Vec
nicht mit identischen Konstruktoren bereitstellen muss. Dies zwingt uns, jede Funktion auf Vec
für jede Instanz von Vec
zu implementieren (da ein Mangel an Musterübereinstimmung impliziert, dass es unter Vec
nicht polymorph sein kann). Was ist in diesem Fall die beste Vorgehensweise?
Informationen zur Laufzeitlänge: haskell hat keine vollständigen abhängigen Typen. Haskell unterscheidet zwischen Laufzeitwerten und Typen. Die Länge des Vec wird also garantiert gelöscht (da die Länge ein Typ (oder eine Art) ist, kein Laufzeitwert, aber haskell erlaubt nicht, dass Typen zur Laufzeit beibehalten werden). – russoulmc