Sagen wir, ich habe das folgende newtype
:
newtype Foo = Foo Integer deriving (Eq, Show)
Gibt es eine prägnante Möglichkeit zwei Foo
's hinzuzufügen:
(Foo 10) + (Foo 5) == Foo 15
oder holen Sie sich das Maximum:
max (Foo 10) (Foo 5) == Foo 5
?
Ich bin neugierig, ob es möglich ist, Funktionen von a
für ein newtype a
zu verwenden, anstatt:
Sie möchten Funktionen vom Typ Integer -> Integer -> Integer
auf Foo -> Foo -> Foo
heben. Um dies zu tun, könnten Sie Utility-Funktionen definieren:
Dann könnten Sie es wie folgt verwenden:
%Vor%Dies hat den Vorteil, dass keine Erweiterung erforderlich ist.
Eine weitere Option ist, die Definition des Foo
newtype zuzulassen, damit Sie eine Instanz von Functor
und Applicative
machen können:
Jetzt können Sie Folgendes tun:
%Vor% Da foo
auf den Typ Integer
spezialisiert ist, verlieren Sie keine Vorteile der Typprüfung.
Sie können dafür auch safe coercions verwenden. Grob verwenden Sie Data.Coerce.coerce
, um den newtype automatisch zu verpacken / auszupacken.
Beachten Sie, dass es bei monomorphen Funktionen wie f
sehr gut funktioniert, weniger bei polymorphen Funktionen wie succ
, da im letzteren Fall eine Typ-Annotation erforderlich ist.
Um mathematische Operationen zu erhalten, müssen Sie Foo
zu einer Instanz der Num
typeclass machen. Dies bedeutet, dass Sie (+)
, (*)
, abs
, signum
, fromInteger
und entweder negate
oder (-)
für Foo
definieren müssen. Sobald Sie diese Funktionen definiert haben, erhalten Sie die restlichen Funktionen, die für Num
kostenlos sind.
Damit max
und ähnliche Funktionen funktionieren, müssen Sie Foo
eine Instanz von Ord
erstellen. Dies erfordert Definitionen von compare
oder (<=)
.
Im Allgemeinen können Sie :t
in ghci verwenden, um den Typ einer Funktion zu finden, der die typeclasses enthält, mit denen sie arbeitet. Dann müssen Sie nur bestimmen, welche minimale Menge von Funktionen Sie für diese Typklasse definieren müssen.