Pourquoi Haskell interpréter mon type Num comme Enum?
-
20-09-2019 - |
Question
Je suis en train de compiler la fonction suivante dans Haskell pour imiter la différenciation d'un polynôme dont les constantes sont spécifiées dans une liste numérique:
diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) [0..]
Haskell refuse de le compiler, me donner la raison suivante:
Could not deduce (Enum a) from the context (Num a)
arising from the arithmetic sequence `0 .. ' at fp1.hs:7:38-42
Possible fix:
add (Enum a) to the context of the type signature for `diff'
In the third argument of `zipWith', namely `[0 .. ]'
In the expression: zipWith (*) (tail coeff) ([0 .. ])
In the definition of `diff':
diff coeff = zipWith (*) (tail coeff) ([0 .. ])
Pourquoi Haskell traite la liste [0..]
comme un type Enum, et comment puis-je résoudre ce problème. Gardez à l'esprit que je veux profiter de l'évaluation paresseuse ici, d'où la liste infinie.
La solution
[0..]
est le sucre syntaxique pour enumFrom 0
, défini dans la classe Enum
. Parce que vous voulez générer une liste de a
s avec [0..]
le compilateur exige a
être en classe Enum
.
Vous pouvez ajouter le Enum a
à la signature de type de la fonction ou le travail autour d'elle en générant un [0..] :: [Integer]
et utiliser pour obtenir un fromInteger
de cette Num
(qui est défini dans la classe [a]
):
diff :: (Num a) => [a] -> [a]
diff [] = error "Polynomial unspecified"
diff coeff = zipWith (*) (tail coeff) (map fromInteger [0..])
Autres conseils
Le type correct de diff
doit être
diff :: (Num a, Enum a) => [a] -> [a]
parce que l'utilisation de [x..]
exige le type d'instancier Enum
.
[0..]
est un raccourci pour enumFrom 0
Voir
Voici un résumé rapide de ce que voit le compilateur quand il regarde cette fonction:
- [0 ..] est une liste de choses qui ont les deux cas Num et Enum. Il doit être Num à cause du « 0 », et il doit être un Enum en raison de la « .. »
- Je me demande d'appliquer (*) aux éléments de coeff et [0 ..] un par un. Étant donné que les deux arguments (*) doivent être du même type et [0 ..] a une instance pour Enum, coeff doit également avoir une instance pour Enum.
- Erreur! La signature de type de diff mentionne seulement que coeff a une instance pour Num, mais je l'ai déjà déterminé qu'il doit au moins avoir une instance pour Enum aussi.