Merkmale in Rust scheinen zumindest oberflächlich Typklassen in Haskell ähnlich zu sein , aber ich habe Leute schreiben sehen, dass es einige Unterschiede zwischen ihnen gibt. Ich habe mich genau gefragt, was diese Unterschiede sind.
157
class Functor f where fmap :: (a -> b) -> (f a -> f b)
; Ein Beispiel für Letzteres istclass Bounded a where maxBound :: a
.std::default
), und Multiparameter-Merkmale funktionieren (einschließlich eines Analogons funktionaler Abhängigkeiten), obwohl AFAIK den ersten privilegierten Parameter umgehen muss. Kein HKT jedoch. Sie stehen auf der Wunschliste der fernen Zukunft, aber noch nicht am Horizont.Antworten:
Im Grunde gibt es keinen großen Unterschied, aber sie sind immer noch da.
Haskell beschreibt Funktionen oder Werte, die in einer Typklasse definiert sind, als 'Methoden', genauso wie Merkmale OOP-Methoden in den Objekten beschreiben, die sie einschließen. Haskell geht jedoch anders mit diesen um und behandelt sie als einzelne Werte, anstatt sie an ein Objekt zu heften, wie dies OOP veranlassen würde. Hier geht es um den offensichtlichsten Unterschied auf Oberflächenebene.
Das einzige, was Rust für eine Weile nicht tun konnte , waren typisierte Merkmale höherer Ordnung , wie die berüchtigten
Functor
undMonad
Typklassen.Dies bedeutet, dass Rostmerkmale nur beschreiben können, was oft als "konkreter Typ" bezeichnet wird, mit anderen Worten, einer ohne generisches Argument. Haskell konnte von Anfang an Typklassen höherer Ordnung erstellen, die Typen verwenden, die denen ähnlicher Funktionen höherer Ordnung ähneln: Verwenden einer, um eine andere zu beschreiben. Für eine gewisse Zeit war dies in Rust nicht möglich, aber seitdem zugehörige Elemente implementiert wurden, sind solche Merkmale alltäglich und idiomatisch geworden.
Wenn wir also Erweiterungen ignorieren, sind sie nicht genau gleich, aber jede kann sich annähern, was die andere tun kann.
Wie in den Kommentaren erwähnt, ist es auch erwähnenswert, dass GHC (Haskells Hauptcompiler) weitere Optionen für Typklassen unterstützt, einschließlich Typklassen mit mehreren Parametern (dh vielen beteiligten Typen) und funktionale Abhängigkeiten , eine schöne Option, die Berechnungen auf Typebene ermöglicht und führt zu Typfamilien . Meines Wissens hat Rust weder funDeps noch Typfamilien, auch wenn dies in Zukunft der Fall sein könnte. †
Alles in allem weisen Merkmale und Typklassen grundlegende Unterschiede auf, die aufgrund ihrer Interaktion dazu führen, dass sie sich verhalten und am Ende ziemlich ähnlich erscheinen.
† Einen schönen Artikel über Haskells Typklassen (einschließlich höher typisierter Klassen) finden Sie hier , und das Kapitel Rust by Example über Merkmale finden Sie hier
quelle
Ich denke, die aktuellen Antworten übersehen die grundlegendsten Unterschiede zwischen Rust-Merkmalen und Haskell-Typklassen. Diese Unterschiede hängen damit zusammen, wie Merkmale mit objektorientierten Sprachkonstrukten zusammenhängen. Informationen hierzu finden Sie im Rust-Buch .
Eine Merkmalsdeklaration erstellt einen Merkmalstyp . Dies bedeutet, dass Sie Variablen eines solchen Typs (oder vielmehr Referenzen des Typs) deklarieren können. Sie können Merkmalstypen auch als Parameter für Funktions-, Strukturfelder und Typparameterinstanziierungen verwenden.
Eine Merkmalsreferenzvariable kann zur Laufzeit Objekte unterschiedlichen Typs enthalten, solange der Laufzeittyp des referenzierten Objekts das Merkmal implementiert.
So funktionieren Typklassen nicht. Typklassen erstellen keine Typen , daher können Sie keine Variablen mit dem Klassennamen deklarieren. Typklassen dienen als Grenzen für Typparameter, aber die Typparameter müssen mit einem konkreten Typ instanziiert werden, nicht mit der Typklasse selbst.
Sie können keine Liste verschiedener Dinge unterschiedlichen Typs haben, die dieselbe Typklasse implementieren. (Stattdessen werden in Haskell existenzielle Typen verwendet, um etwas Ähnliches auszudrücken.) Hinweis 1
Merkmalsmethoden können dynamisch versendet werden . Dies hängt stark mit den Dingen zusammen, die im obigen Abschnitt beschrieben werden.
Dynamischer Versand bedeutet, dass der Laufzeittyp des Objekts, auf das ein Referenzpunkt verweist, verwendet wird, um zu bestimmen, welche Methode über die Referenz aufgerufen wird.
Auch hierfür werden in Haskell existenzielle Typen verwendet.
Abschließend
Es scheint mir, dass Merkmale in vielerlei Hinsicht das gleiche Konzept wie Typklassen sind. Darüber hinaus verfügen sie über die Funktionalität objektorientierter Schnittstellen.
Andererseits sind die Typklassen von Haskell weiter fortgeschritten. Haskell hat zum Beispiel höherwertige Typen und Erweiterungen wie Typklassen mit mehreren Parametern.
Hinweis 1 : Neuere Versionen von Rust verfügen über ein Update, um die Verwendung von Merkmalsnamen als Typen und die Verwendung von Merkmalsnamen als Grenzen zu unterscheiden. In einem Merkmalstyp wird dem Namen das
dyn
Schlüsselwort vorangestellt . Weitere Informationen finden Sie beispielsweise in dieser Antwort .quelle
dyn Trait
als eine Form existenzieller Typisierung zu verstehen, da sie sich auf Merkmale / Typklassen beziehen. Wir könnendyn
einen Operator an Grenzen betrachten, der sie auf Typen projiziert, ddyn : List Bound -> Type
. H. Wenn wir diese Idee zu Haskell bringen und in Bezug auf "Sie können also keine Variablen mit dem Klassennamen deklarieren.", Können wir dies indirekt in Haskell tun :data Dyn (c :: * -> Constraint) = forall (t :: Type). c t => D t
. Nachdem wir dies definiert haben, können wir mit arbeiten[D True, D "abc", D 42] :: [D Show]
.Rusts "Merkmale" sind analog zu Haskells Typklassen.
Der Hauptunterschied zu Haskell besteht darin, dass Merkmale nur für Ausdrücke mit Punktnotation eingreifen, dh für die Form a.foo (b).
Haskell-Typklassen erstrecken sich auf Typen höherer Ordnung. Rostmerkmale unterstützen nur keine Typen höherer Ordnung, da sie in der gesamten Sprache fehlen, dh es ist kein philosophischer Unterschied zwischen Merkmalen und Typklassen
quelle
Default
Merkmal, das keine Methoden enthält, sondern nur Funktionen, die nicht mit Methoden verknüpft sind.