Pregunta

Tengo un problema sobre el que quiero obtener más información y cómo evitarlo. Tengo este código

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

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

Lo que genera el siguiente error

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)

Ahora, sé que este error (gracias a irc.freenode.net # haskell) es el resultado de la función de división

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

Sin embargo, no sé qué hacer. Mi firma de función avg no debería tener nada que ver con las peculiaridades de los operadores de división (que requieren la clase de tipo Fractional ). Entonces, me quedo pensando que la forma correcta de superar esto es emitiendo un tipo que implique que Fractional typeclass pero no tengo idea de cómo, o incluso si esto es correcto. ¿Alguna idea?

¿Fue útil?

Solución

  

Mi firma de función avg no debería tener nada que ver con las peculiaridades del operador de división

¿Por qué es eso? Si desea calcular el promedio de un conjunto de números enteros, tendrá que dividir en algún momento, por lo que tendrá que convertirlos de números enteros al tipo de soporte de división de su elección. Una mirada cercana a la clase Num (: i Num en ghci) revela un problema con el tipo de avg : Num no tiene suficientes métodos, básicamente suficientes para sumar, multiplicar y restar. No hay garantía de que el número que le doy a avg se pueda convertir a Double en absoluto.

Si ingresa una función sin tipo para calcular un promedio, Haskell responde con el tipo más genérico posible:

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

Entonces, ese es el tipo correcto de avg .

Puede notar que avg [1,2,3 :: Integer] da un error de tipo. Puede evitar eso pasando primero el argumento a toRational o fromIntegral , que utilizan las instancias Real y Integral para Integer , respectivamente.


Con respecto a la expresión sum [1,2,3] / len [1,2,3] : Es cierto que un número literal como 1 tiene el tipo de Num a = > a , que llama a fromInteger en cualquier tipo que resulte ser, pero una expresión como 1/2 tiene un tipo más específico de Fraccional a = > un , que puede ver si solicita el tipo de esa expresión en lugar de imprimirla.

Algo que podría ser útil es : set -Wall en ghci, que activa muchas advertencias cada vez que se elige un tipo predeterminado para usted, lo que da una pista de que el tipo más genérico ya no será correcto.

Otros consejos

Estás restringiendo demasiado el tipo de promedio. Use la versión más general, avg :: (Fractional a) = > [a] - > a

hhm, el verdadero problema es si es un tipo integral que desea convertir a un tipo fraccionario, pero si es un tipo fraccional, desea dejarlo solo.

Prueba esto

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

He encontrado este problema. Lo mejor que he logrado hacer es tener dos funciones para promediar: una para integrales y otra para fraccionales:

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)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top