Gegeben :
data Foo =
FooString String
…
class Fooable a where --(is this a good way to name this?)
toFoo :: a -> Foo
Ich möchte String
eine Instanz erstellen von Fooable
:
instance Fooable String where
toFoo = FooString
GHC beschwert sich dann:
Illegal instance declaration for `Fooable String'
(All instance types must be of the form (T t1 ... tn)
where T is not a synonym.
Use -XTypeSynonymInstances if you want to disable this.)
In the instance declaration for `Fooable String'
Wenn ich stattdessen benutze [Char]
:
instance Fooable [Char] where
toFoo = FooString
GHC beschwert sich:
Illegal instance declaration for `Fooable [Char]'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are type *variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Fooable [Char]'
Frage :
- Warum kann ich keinen String und keine Instanz einer Typklasse erstellen?
- GHC scheint bereit zu sein, mich damit davonkommen zu lassen, wenn ich eine zusätzliche Flagge hinzufüge. Ist das eine gute Idee?
haskell
ghc
typeclass
type-systems
John F. Miller
quelle
quelle
{-# LANGUAGE FlexibleInstances #-}
(oder ein anderes Pragma) oben in Ihre .hs-Datei einfügen können.Antworten:
Dies liegt daran, dass
String
es sich nur um einen Typalias für handelt[Char]
, bei dem es sich lediglich um die Anwendung des Typkonstruktors[]
auf den TypChar
handelt. Dies wäre also von der Form([] Char)
. Das ist nicht von der Form,(T a1 .. an)
weilChar
es keine Typvariable ist.Der Grund für diese Einschränkung besteht darin, überlappende Instanzen zu verhindern. Nehmen wir zum Beispiel an, Sie hatten eine
instance Fooable [Char]
, und später kam jemand und definierte eineinstance Fooable [a]
. Jetzt kann der Compiler nicht mehr herausfinden, welches Sie verwenden möchten, und gibt Ihnen einen Fehler aus.Durch die Verwendung
-XFlexibleInstances
versprechen Sie dem Compiler grundsätzlich, keine solchen Instanzen zu definieren.Je nachdem, was Sie erreichen möchten, ist es möglicherweise besser, einen Wrapper zu definieren:
quelle
instance Fooable [a]
. Gibt es eine Möglichkeit, dietoFoo
Funktion anders zu verhalten, wenna
es sich um ein Zeichen handelt?-XOverlappingInstances
die dies ermöglicht und die spezifischste Instanz auswählt. Weitere Informationen finden Sie im GHC-Benutzerhandbuch .Bei klassischen Haskell98-Typklassen treten zwei Einschränkungen auf:
Diese belastenden Einschränkungen werden durch zwei Spracherweiterungen aufgehoben:
-XTypeSynonymInstances
Hiermit können Sie Typ-Synoymen (wie
String
für[Char]
) verwenden und:-XFlexibleInstances
Dadurch werden die Einschränkungen für Instanztypen aufgehoben, die die Form haben,
T a b ..
in der die Parameter Typvariablen sind. Mit dem-XFlexibleInstances
Flag kann der Kopf der Instanzdeklaration beliebige verschachtelte Typen erwähnen.Beachten Sie, dass das Aufheben dieser Einschränkungen manchmal zu überlappenden Instanzen führen kann. Zu diesem Zeitpunkt ist möglicherweise eine zusätzliche Spracherweiterung erforderlich, um die Mehrdeutigkeit zu beheben, sodass GHC eine Instanz für Sie auswählen kann.
Referenzen: :
quelle
FlexibleInstances sind in den meisten Fällen keine gute Antwort. Bessere Alternativen sind das Umschließen des Strings in einen neuen Typ oder das Einführen einer Hilfsklasse wie folgt:
Siehe auch: http://www.haskell.org/haskellwiki/List_instance
quelle
Wenn Sie diese Antworten ergänzen und die Einschränkungen nicht aufheben möchten, kann es Fälle geben, in denen es sinnvoll sein kann, Ihren String in einen neuen Typ zu verpacken, der eine Instanz einer Klasse sein kann. Der Kompromiss wäre potenzielle Hässlichkeit, wenn Sie Ihren Code ein- und auspacken müssen.
quelle