Comment faire correspondre les types rigides dans une instance de classe de type?
Question
Je pensais que je voudrais essayer modéliser une intégration numérique sur les quantités de vecteur de différentes dimensionnalité, et compris que les classes de type étaient la voie à suivre. Je besoin de quelque chose pour définir la différence entre les deux valeurs et mettre à l'échelle par un multiplicateur (pour obtenir le dérivé), ainsi que d'être en mesure de prendre la fonction de la distance.
Jusqu'à présent je:
class Integratable a where
difference :: a -> a -> a
scale :: Num b => a -> b -> a
distance :: Num b => a -> a -> b
data Num a => Vector a = Vector1D a | Vector2D a a
instance Num a => Integratable (Vector a) where
difference (Vector1D x1) (Vector1D x2) = Vector1D (x1 - x2)
scale (Vector1D x) m = Vector1D (x * m)
distance (Vector1D x1) (Vector1D x2) = x1 - x2
difference (Vector2D x1 y1) (Vector2D x2 y2) = Vector2D (x1 - x2) (y1 - y2)
scale (Vector2D x y) m = Vector2D (x * m) (y * m)
distance (Vector2D x1 y1) (Vector2D x2 y2) = sqrt((x1-x2)*(x1-x2)
+ (y1-y2)*(y1-y2))
Malheureusement, il y a quelques problèmes ici que je ne l'ai pas compris comment résoudre. Tout d'abord, la fonction scale
donne des erreurs. GHC ne peut pas dire que m
et x
sont compatibles depuis la restriction de type rigide Num
est donnée dans l'instance dans un cas, et dans le type de Vector
dans l'autre ... Est-il possible de préciser que x
et m
sont les même type?
(je me rends compte, en fait, que même si x
et m
sont à la fois Num
, ils ne peuvent pas être même Num
. Comment puis-je le préciser? Si je ne peux pas le comprendre avec Num
, en utilisant Double
serait bien, mais je préfère le garder en général.)
Il y a un problème similaire avec distance
. Toute tentative de préciser que le type de retour est Num
échoue, car il ne peut pas dire dans la définition d'instance a
va contenir des valeurs qui sont compatibles avec b
.
La solution
EDIT: Il me semble maintenant que l'article sur dépendances fonctionnelles de la HaskellWiki fournit les informations clés dans la meilleure forme que je peux trouver, alors je vous suggère la lecture qu'au lieu de ma réponse ici. Je ne suis pas enlever le reste du contenu, mais, comme il l'indique clairement (je l'espère) pourquoi IFD sont utiles ici.
Outre le regroupement de question des définitions qui a Dave sur ...
(je me rends compte, en fait, que même si
x
etm
sont à la foisNum
, ils ne peuvent pas être mêmeNum
. Comment puis-je le préciser? Si je ne peux pas le comprendre avecNum
, en utilisantDouble
serait bien, mais je préfère le garder en général.)
Ceci est le principal problème, en fait. Vous ne pouvez pas multiplier un Integer
par un Float
, disons. En effet, vous avez besoin du x
et m
à l'échelle pour être du même type.
En outre, un problème similaire se pose avec la distance, avec la complication supplémentaire que sqrt
a besoin d'un argument Floating
. Donc, je suppose que vous auriez besoin de mentionner que quelque part aussi. (Très probablement sur l'instance, je suppose).
EDIT:. OK, car sqrt
ne fonctionne que sur les valeurs Floating
, vous pouvez rouler un pour ceux classe de types upCast Float
s à Double
s en cas de besoin
Une autre idée consiste à avoir une Scalable
de classe de types:
data Vector a = Vector1D a | Vector2D a a deriving (Show)
class Scalable a b | a -> b where
scale :: a -> b -> a
instance (Num a) => Scalable (Vector a) a where
scale (Vector1D x) m = (Vector1D (x * m))
scale (Vector2D x y) m = (Vector2D (x * m) (y * m))
Il utilise un soi-disant dépendance fonctionnelle dans la définition de Scalable
. En fait, en essayant de se rappeler la syntaxe pour cela, j'ai trouvé ce lien ... Je suppose que vous devriez ne pas tenir compte de mon inférieur tentative d'être utile et lire les informations de qualité là-bas. ; -)
Je pense que vous devriez être en mesure d'utiliser pour résoudre votre problème d'origine.
Autres conseils
Pour fixer la deuxième erreur, je pense que vous devez réorganiser vos définitions dans la déclaration d'instance. D'abord les deux équations pour difference
, puis les équations pour scale
, alors à la fois pour distance
.