Question

J'ai un problème sur lequel je veux en savoir plus et comment éviter. J'ai ce code

len :: (Num r ) => [a] -> r
len [] = 0
len xs = 1 + len ( tail xs )

avg :: (Num t) => [t] -> Double
avg xs = ( sum xs ) / ( len xs )

Qui rend l'erreur suivante

len.hs:6:9:
    Couldn't match expected type `Double' against inferred type `t'
      `t' is a rigid type variable bound by
          the type signature for `avg' at len.hs:5:12
    In the expression: (sum xs) / (len xs)
    In the definition of `avg': avg xs = (sum xs) / (len xs)

Maintenant, je sais que cette erreur (grâce à irc.freenode.net # haskell) est le résultat de la fonction de division

(/) :: (Fractional a) => a -> a -> a

Cependant, je ne sais pas quoi faire. Ma signature de fonction avg ne devrait avoir aucun rapport avec les excentivants d'opérateurs de division (nécessitant la classe de type Fractional ). Donc, je suis parti pour penser que la bonne façon de surmonter ceci est de choisir un type qui implicite leur classe Fractional mais je ne sais pas comment, ni même si c'est correct? Des idées?

Était-ce utile?

La solution

  La

signature de ma fonction avg ne doit avoir aucun rapport avec les défauts de l'opérateur de division

Pourquoi ça? Si vous souhaitez calculer la moyenne d'un groupe d'entiers, vous devrez diviser à un moment donné. Vous devrez donc les convertir d'Integers au type prenant en charge la division de votre choix. Un examen attentif de la classe Num (: i Num en ghci) révèle un problème avec le type de avg : Num n'a pas assez de méthodes, c'est-à-dire assez pour additionner, multiplier et soustraire. Rien ne garantit que le numéro que je donne à avg puisse être converti en Double .

Si vous entrez une fonction non typée pour calculer une moyenne, Haskell répond avec le type le plus générique possible:

Prelude List> :type \x -> sum x / genericLength x
\x -> sum x / genericLength x :: (Fractional a) => [a] -> a

C'est donc le bon type de avg .

Vous remarquerez peut-être que avg [1,2,3 :: Integer] génère une erreur de type. Vous pouvez contourner cela en passant l'argument à toRational ou fromIntegral , qui utilise les instances Real et Integral . pour entier , respectivement.

À propos de l'expression sum [1,2,3] / len [1,2,3] : Il est vrai qu'un nombre littéral tel que 1 a le type de Num a = > a , qui appelle fromInteger quel que soit le type utilisé, mais une expression comme 1/2 a un type plus spécifique de Fractional a = > un , que vous pouvez voir si vous demandez le type de cette expression au lieu de l’imprimer.

Un élément qui pourrait être utile est : set -Wall dans ghci, qui active de nombreux avertissements chaque fois qu'un type par défaut est choisi, ce qui indique que le type le plus générique pourrait ne plus l'être. correct.

Autres conseils

Vous êtes trop contraignant pour le type d'avg. Utilisez la version plus générale, avg :: (Fractional a) = > [a] - > un

hhm, le vrai problème est de savoir si c'est un type entier que vous voulez convertir en un type fractionnel, mais s'il s'agit d'un type fractionnel, vous voulez le laisser seul.

Essayez ceci

fromRational ((sum xs) % (leng xs))

J'ai rencontré ce problème. Ce que j’ai le mieux réussi à faire est d’avoir deux fonctions pour la moyenne: une pour les intégrales et une pour les fractions:

avgInt :: (Integral i, Fractional f) => [i] -> f
avgInt xs = fromIntegral (sum xs) / fromIntegral (length xs)

avgFrac :: (Fractional f) => [f] -> f
avgFrac xs = sum xs / fromIntegral (length xs)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top