2012-09-11 4 views
0

Dans Haskell, j'ai quelques problèmes pour définir des fonctions car les types de mes arguments ne correspondent pas au type requis.Pourquoi est-ce que je reçois une erreur de type?

Par exemple, je voudrais écrire une fonction qui prend un n :: Int et produit la liste des entiers de 1 à floor de la racine carrée de n. Par conséquent je voudrais avoir une fonction telle que:

list :: Int -> [Int] 

Au départ, je défini la fonction comme suit:

list :: Int -> [Int] 

list n = [1 .. floor (sqrt n)] 

Quand je chargé le sript, il y a un message d'erreur des types qui ne correspondent pas. Cependant, je ne suis pas sûr de ne pas correspondre au type de la fonction sqrt ou de la fonction floor. Le message d'erreur est le suivante:

No instance for (Floating Int) 
    arising from a use of 'sqrt' at pe142.hs:6:22-27 
Possible fix: add an instance declaration for (Floating Int) 
In the first argument of 'floor', namely '(sqrt n)' 
In the expression: floor (sqrt n) 
In the expression: [1 .. floor (sqrt n)] 
Failed, modules loaded: none. 

Quelqu'un pourrait-il me expliquer ce qui cause l'erreur et comment il peut être fixé?

Répondre

6

sqrt nécessite un argument de la classe Floating, par ex. un Double. Vous lui passez un Int, qui n'est pas une instance de la classe Floating - c'est ce que le message d'erreur vous dit. Pour corriger l'erreur, convertissez votre Int en Double avant d'appeler sqrt. Vous pouvez utiliser la fonction fromIntegral pour cela.

4

Quand j'essaie ceci:

list :: Int -> [Int] 
list n = [1 .. floor (sqrt n)] 

Je reçois cette erreur:

../src/scratch.hs:15:16: 
    No instance for (RealFrac Int) 
     arising from a use of `floor' 
    Possible fix: add an instance declaration for (RealFrac Int) 
    In the expression: floor (sqrt n) 
    In the expression: [1 .. floor (sqrt n)] 
    In an equation for `list': list n = [1 .. floor (sqrt n)] 

../src/scratch.hs:15:23: 
    No instance for (Floating Int) 
     arising from a use of `sqrt' 
    Possible fix: add an instance declaration for (Floating Int) 
    In the first argument of `floor', namely `(sqrt n)' 
    In the expression: floor (sqrt n) 
    In the expression: [1 .. floor (sqrt n)] 

Ce que ces erreurs signifient est la suivante:

  • La fonction floor ne peut pas accepter une argument du type Int. Son argument doit être de type "fraction réelle". (Cela n'a pas de sens de demander l'étage des nombres dont le type ne supporte que des nombres entiers.)
  • La fonction sqrt ne peut pas non plus accepter un argument de type Int. Son argument doit être d'un type à virgule flottante. (Racines carrées sont généralement irrationnelles, nous avons donc besoin d'un type à virgule flottante.)

Vous constaterez que Haskell est très, très pointilleux sur ce que les fonctions numériques peuvent être appliquées à quels types numériques, très pointilleux sur ce types ces fonctions retournent, et elle n'effectue pratiquement aucun casting implicite. J'essaie généralement de laisser le compilateur déduire les types en code numérique, car la hiérarchie des classes est vraiment complexe. Si nous laissons la déclaration de type pour votre fonction, le compilateur infère ce type:

list :: (Floating a, Integral t, RealFrac a) => a -> [t] 

Ie, votre fonction de fonction list prend un virgule flottante « fraction réelle » comme argument, et produit une liste de nombres entiers comme son résultat. Ainsi, par exemple, list peut prendre un argument de type Double et produire un [Integer].Mais même en omettant les déclarations de type, cela ne signifie pas que vous n'aurez pas de problèmes et vous devrez souvent utiliser des distributions explicites; le plus typique est que vous devez utiliser la fonction fromIntegral pour convertir des types entiers en types fractionnaires.

1

sqrt a la signature de type suivant:

Floating a => a -> a 

Cela signifie que sqrt prend un argument de type A et renvoie un argument de type a. La restitution est que a doit être un type dans la classe de type Flottant, généralement simple ou double. Int est pas dans la classe de type flottant, donc vous devez convertir n à quelque chose qui est dans la classe de type flottant, vous pouvez le faire en ajoutant un appel à fromIntegral:

list n = [1 .. floor (sqrt (fromIntegral n))] 
0

Cette question se demande environ une fois la semaine. (Ce n'est pas une plainte contre vous, juste une observation, évidemment, cela déroute pas mal de gens.)

En résumé, sqrt ne fonctionne pas pour les entiers, seulement pour les nombres à virgule flottante. (Par exemple, cela ne fonctionne pas pour Int, mais cela fonctionne pour Double.) Dans certains langages de programmation, les entiers sont toujours automatiquement "promus" aux nombres à virgule flottante dans de tels cas; mais dans Haskell, vous devez le faire manuellement. La solution, comme une demi-douzaine d'autres personnes ont sans doute déjà écrit, consiste à y coller un fromIntegral pour convertir des entiers en virgule flottante. Vous y avez déjà floor, ce qui vous permet de revenir à un nombre entier par la suite, comme vous vous en doutez.

Questions connexes