Pourquoi Haskell lancer une erreur « ne peut pas construire le type infini »?
-
20-09-2019 - |
Question
J'ai écrit le code suivant dans Haskell pour calculer le produit scalaire de deux vecteurs, mais ne peut pas le compiler en raison de l'erreur suivante:
cannot construct infinite type: a = [a] When generalising the type(s) for dot'
dot :: (Num a) => [a] -> [a] -> a
[] `dot` [] = 0
x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)
J'ai examiné cette question à l'avance à titre indicatif. Pour autant que je peux dire, les types sont corrects. x, y et les deux [] 's sont des listes, et la fonction renvoie un nombre.
Qu'est-ce qui ne va pas?
La solution
Vous confondez la syntaxe pour une liste de deux éléments [x, y]
avec la syntaxe pour diviser une liste dans le premier élément et le reste de la liste (x:y)
. Essayez ceci:
dot :: (Num a) => [a] -> [a] -> a
[] `dot` [] = 0
x@(xi:xs) `dot` y@(yi:ys) = xi*yi + (xs `dot` ys)
Les motifs de @
sont également inutiles, d'ailleurs.
Autres conseils
réponse Ganesh est sur place. Permettez-moi de préciser brièvement sur la signification d'un « type infini ».
dot
a cette définition de type:
dot :: (Num a) => [a] -> [a] -> a
Cela signifie que dot
prend deux listes d'éléments de Num
et renvoie un Num
. Votre définition inclut cette ligne:
x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)
Depuis, comme Ganesh souligne, [xi,xs]
est une liste composée de deux éléments, xi
et xs
devraient être Num
s. Idem pour yi
et ys
. Mais ils sont passés comme arguments à dot
:
xs `dot` ys
Cela signifie que xs
et ys
doivent être des listes de Num
s. Cela conduit à une contradiction.
Une autre façon de regarder cela, est à un moment oublier la définition du type de dot
. Cette ligne,
x@[xi,xs] `dot` y@[yi,ys] = xi*yi + (xs `dot` ys)
indique que dot
prend deux listes dont les éléments sont les paramètres appropriés pour dot
. Mais la seule façon pour que de donner un sens, est si ces listes sont infiniment imbriqués . Ce n'est pas autorisé, ni raisonnable.