web-dev-qa-db-fra.com

Pourquoi ce code Haskell génère-t-il l'erreur "type infini"?

Je suis nouveau à Haskell et je suis confronté à une erreur "impossible de construire un type infini" que je ne peux pas comprendre. 

En fait, au-delà de cela, je n’ai pas été en mesure de trouver une bonne explication de ce que cette erreur signifie même, alors si vous pouviez aller au-delà de ma question de base et expliquer l’erreur "type infini", je l’apprécierais vraiment.

Voici le code: 

intersperse :: a -> [[a]] -> [a]

-- intersperse '*' ["foo","bar","baz","quux"] 
--  should produce the following:
--  "foo*bar*baz*quux"

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]]
--  should produce the following:
--  [1,2,3,-99,4,5,6,-99,7,8,9]

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:y:xs) = x:s:y:intersperse s xs

Et voici l'erreur d'essayer de le charger dans l'interprète: 

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted )

chapter.3.ending.real.world.haskell.exercises.hs:147:0:
Occurs check: cannot construct the infinite type: a = [a]
When generalising the type(s) for `intersperse'
Failed, modules loaded: none.

Merci.

-

Voici quelques corrections du code et une directive générale pour traiter l'erreur "type infini" dans Haskell:

Code corrigé

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) =  x ++ s:intersperse s xs 

Quel était le problème:

Ma signature de type indique que le deuxième paramètre à intercaler est une liste de listes. Par conséquent, lorsque le motif correspond à "s (x: y: xs)", x et y deviennent lists . Et pourtant, je traitais x et y comme des éléments, pas des listes. 

Guide pour traiter l'erreur "type infini":

La plupart du temps, lorsque vous obtenez cette erreur, vous avez oublié les types des différentes variables avec lesquelles vous traitez et vous avez essayé d'utiliser une variable comme s'il s'agissait d'un autre type que ce dont il s'agit. Examinez attentivement le type de tout par rapport à la façon dont vous l’utilisez, et le problème sera généralement découvert.

67
Charlie Flowers

Le problème se trouve dans la dernière clause, où vous traitez x et y en tant qu'éléments, alors qu'ils sont des listes. Cela fonctionnera:

intersperse _ [] = []
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs

L'erreur de type infini se produit car l'opérateur: a le type a -> [a] -> [a], alors que vous le traitez comme [a] -> a -> [a], ce qui signifie que [a] doit être identifié par a, ce qui voudrait dire que a est une liste infiniment imbriquée. Ce n'est pas permis (et pas ce que vous voulez dire, en tout cas).

Edit: / il y a aussi un autre bogue dans le code ci-dessus. CA devrait etre:

intersperse _ [] = []
intersperse _ [x] = x
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs
28
Stephan202

Ajouter souvent une définition de type explicite peut donner plus de sens au message d'erreur de type du compilateur. Mais dans ce cas, le typage explicite aggrave le message d'erreur du compilateur.

Regardez ce qui se passe quand je laisse ghc deviner le type d'interpolation:

Occurs check: cannot construct the infinite type: a = [a]
  Expected type: [a] -> [[a]] -> [[a]]
  Inferred type: [a] -> [[a]] -> [a]
In the second argument of `(:)', namely `intersperse s xs'
In the second argument of `(:)', namely `y : intersperse s xs'

Cela pointe clairement vers le bug dans le code. En utilisant cette technique, vous n'avez pas à regarder tout et à réfléchir aux types, comme d'autres l'ont suggéré.

4
Joey

Je peux me tromper, mais il semble que vous essayez de résoudre un problème plus difficile. Votre version de intersperse n'interpelle pas simplement la valeur avec le tableau, mais l'aplatit également d'un niveau.

Le module List de Haskell fournit en fait une fonction intersperse. Il met la valeur donnée entre chaque élément de la liste. Par exemple:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9]
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"]

Je suppose que c'est ce que vous voulez faire parce que c'est ce que mon professeur voulait que nous fassions lorsque j'apprenais Haskell. Je pourrais bien sûr être totalement absent.

2
Samir Talwar

J'ai aussi trouvé this qui explique le sens de l'erreur.

Chaque fois que l'interprète/compilateur me donne cette erreur, c'est parce que j'utilise un Tuple paramétré par le type comme paramètre formel. Tout fonctionne correctement en supprimant la définition de type de la fonction, qui contenait des variables de type.

Je n'arrive toujours pas à comprendre comment résoudre le problème et conserver la définition du type de fonction.

0
Dacav