2012-04-29 17 views
5

No entiendo por qué la función siguiente funciona:Confusión con el tipo de inferencia Haskell

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > fromIntegral n 

pero el siguiente no:

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

que arroja el error

Could not deduce (n ~ Int) 
    from the context (Integral n) 
     bound by the type signature for 
       isLongerThanN' :: Integral n => n -> [a] -> Bool 
     at blah.hs:140:1-35 
     `n' is a rigid type variable bound by 
      the type signature for 
      isLongerThanN' :: Integral n => n -> [a] -> Bool 
      at blah.hs:140:1 
    In the second argument of `(>)', namely `n' 
    In the expression: length xs > n 
    In an equation for `isLongerThanN'': 
     isLongerThanN' n xs = length xs > n 

(que probablemente he entendido mal)

En todo caso, esperaría que fuera al revés, ya que de Integral está efectivamente ampliando el tipo de variable n.

+8

No escriba 'si foo entonces la verdadera cosa false'. Es lo mismo que simplemente 'foo'. – hammar

+1

tienes razón, gracias; Lo he modificado, pero esa no es la pregunta – Inept

+4

Es por eso que no lo publicó como una respuesta ... – Jasper

Respuesta

12

Considérese la expresión que no funciona

isLongerThanN' :: Integral n => n -> [a] -> Bool 
isLongerThanN' n xs = length xs > n 

n puede ser cualquier tipo entero-y, por lo que se puede pasar un Integer o Word o Int. (>) tiene tipo Ord a => a -> a -> Bool, por lo que tanto su operando izquierdo como derecho deben ser del mismo tipo. length xs devuelve Int por lo que este tipo tiene que ser eso. Pero, n puede ser cualquier Integral, no necesariamente Int, por lo que necesitamos alguna manera de permitir que n se convierta a Int. Esto es lo que fromIntegral hace (el hecho de que también permite que n sea cualquier Num es básicamente irrelevante).

Podríamos ampliar la versión de trabajo para parecerse a:

toInt :: Integral n => n -> Int 
toInt = fromIntegral 

isLongerThanN :: Integral n => n -> [a] -> Bool 
isLongerThanN n xs = length xs > toInt n 

que hace que sea más claro que estamos usando una versión especializada de fromIntegral.

(Tenga en cuenta que isLongerThanN n xs = fromIntegral (length xs) > n funciona también, porque permite que el resultado de length para que coincida con el tipo de n.)

+2

Sin embargo, tenga en cuenta que la elección de cuál convertir puede afectar el resultado; con el último ejemplo 'isLongerThanN (0 :: Word8) [1..256] == False' debido al desbordamiento. – hammar

+0

Oh bien, lo entiendo. Muchas gracias. Por qué la versión no funcional no funciona no fue el problema para mí, pero estaba leyendo la firma de tipo fromIntegral :: (Num b, Integral a) => a -> b erróneamente. – Inept

Cuestiones relacionadas