Donné :
data Foo =
FooString String
…
class Fooable a where --(is this a good way to name this?)
toFoo :: a -> Foo
Je veux créer String
une instance de Fooable
:
instance Fooable String where
toFoo = FooString
GHC se plaint alors:
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'
Si à la place j'utilise [Char]
:
instance Fooable [Char] where
toFoo = FooString
GHC se plaint:
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]'
Question :
- Pourquoi ne puis-je pas créer une chaîne et une instance d'une classe de types?
- GHC semble prêt à me laisser m'en tirer si j'ajoute un drapeau supplémentaire. Est-ce une bonne idée?
haskell
ghc
typeclass
type-systems
John F. Miller
la source
la source
{-# LANGUAGE FlexibleInstances #-}
(ou tout autre pragma) en haut de votre fichier .hs.Réponses:
Cela est dû au
String
fait qu'il s'agit simplement d'un alias de type pour[Char]
, qui est juste l'application du constructeur de type[]
sur le typeChar
, donc ce serait de la forme([] Char)
. qui n'est pas de la forme(T a1 .. an)
carChar
n'est pas une variable de type.La raison de cette restriction est d'éviter le chevauchement des instances. Par exemple, disons que vous avez eu un
instance Fooable [Char]
, puis quelqu'un est venu plus tard et a défini uninstance Fooable [a]
. Maintenant, le compilateur ne sera pas en mesure de déterminer celui que vous vouliez utiliser et vous donnera une erreur.En utilisant
-XFlexibleInstances
, vous promettez au compilateur de ne pas définir de telles instances.En fonction de ce que vous essayez d'accomplir, il peut être préférable de définir un wrapper:
newtype Wrapper = Wrapper String instance Fooable Wrapper where ...
la source
instance Fooable [a]
aussi. Existe-t-il un moyen de faire en sorte que latoFoo
fonction se comporte différemment s'ila
s'agit d'un Char?-XOverlappingInstances
qui permet cela, et choisissez l'instance la plus spécifique. Consultez le guide de l'utilisateur du GHC pour plus de détails .Vous rencontrez deux limitations des classes de types classiques Haskell98:
Ces lourdes restrictions sont levées par deux extensions de langue:
-XTypeSynonymInstances
qui vous permet d'utiliser des synoyms de type (comme
String
pour[Char]
), et:-XFlexibleInstances
qui lèvent les restrictions sur les types d'instances étant de la forme
T a b ..
où les paramètres sont des variables de type. L'-XFlexibleInstances
indicateur permet à la tête de la déclaration d'instance de mentionner des types imbriqués arbitraires.Notez que la levée de ces restrictions peut parfois entraîner des instances qui se chevauchent , auquel cas une extension de langue supplémentaire peut être nécessaire pour résoudre l'ambiguïté, permettant à GHC de choisir une instance pour vous.
Références ::
la source
Les instances flexibles ne sont pas une bonne réponse dans la plupart des cas. De meilleures alternatives enveloppent la chaîne dans un nouveau type ou introduisent une classe d'assistance comme ceci:
class Element a where listToFoo :: [a] -> Foo instance Element Char where listToFoo = FooString instance Element a => Fooable [a] where toFoo = listToFoo
Voir aussi: http://www.haskell.org/haskellwiki/List_instance
la source
En ajoutant à ces réponses, si vous n'êtes pas à l'aise avec la levée des restrictions, il peut y avoir des cas où il pourrait être judicieux d'envelopper votre String dans un nouveau type, qui peut être une instance d'une classe. Le compromis serait la laideur potentielle, avoir à envelopper et à déballer votre code.
la source