2012-04-10 17 views
11

que era tanto sueño que escribí el siguiente código (modificado para mostrar sólo la confusión):Haskell: ¿Por qué no hay desajuste de tipo (y por qué compila esto)?

fac s = take 10 [s, s `mod` 1 ..] 

maxFactor x = if (s == []) 
       then x 
       else head <-- this should be 'head x' instead of just 'head' 
    where s = fac x 

Sin embargo, esta carga en ghci (y compila) muy bien. Cuando ejecuté maxFactor 1, se queja (por supuesto):

<interactive>:0:1: 
    No instance for (Integral ([a0] -> a0)) 
     arising from a use of `maxFactor' 
    Possible fix: 
     add an instance declaration for (Integral ([a0] -> a0)) 
    In the expression: maxFactor 1 
    In an equation for `it': it = maxFactor 1 

<interactive>:0:11: 
    No instance for (Num ([a0] -> a0)) 
     arising from the literal `1' 
    Possible fix: add an instance declaration for (Num ([a0] -> a0)) 
    In the first argument of `maxFactor', namely `1' 
    In the expression: maxFactor 1 
    In an equation for `it': it = maxFactor 1 

Sin embargo, no entiendo este comportamiento:

fac 's tipo es:

fac :: Integral a => a -> [a] 

mientras maxFactor' s tipo es:

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a 

Does not mean th th e siguiente:

  1. la primera entrada a fac debe ser de clase de tipos Integral (por ejemplo, fac 10);
  2. ya que en la definición de maxFactor, no es fac x, x debe ser también de clase de tipos Integral, por lo tanto, el tipo maxFactor 's sería empezar con algo como maxFactor :: (Integral a) => a -> ... luego algo más? Sin embargo, si ese es el caso, entonces ¿por qué este código se compila ya que el retorno de maxFactor puede ser x o head, que al seguir esta línea de razonamiento, no tiene el mismo tipo?

¿Qué es lo que falta aquí?

¡Gracias por cualquier entrada por adelantado!

+1

Este tipo de problema puede surgir de una manera mucho más simple. Sospecho (pero no soy un experto) que puede suceder cuando el verificador de tipos no puede reducir suficientemente una expresión. Por ejemplo, foo x = 1 + x; bar = foo head - fallará, pero foo x = 1 + x; bar x = foo head: se compilará. – Sarah

+0

@Sarah: el ejemplo que proporciona no comprueba de forma automática debido a la restricción de monomorfismo; si agrega pragma, tipea (aunque hay un problema sutil: GHCi infiere tipo 'Num ([a] → a) ⇒ [a] → a' y usted no puede declarar' bar' con este tipo, usted necesitaría FlexibleContexts para eso) – Vitus

+0

Por lo que vale, si compila con '-Wall' (o lo agrega a sus opciones de ghci predeterminadas, para que ghci" compile "con' -Wall') obtendrá una advertencia porque no puso un tipo firma en 'maxFactor'. Entonces, presumiblemente, escribirás 'maxFactor :: Integral a => a -> a' y no podrá compilarse. – MatrixFrog

Respuesta

9

en maxFactor el compilador infiere que el argumento de la función x necesariamente tiene el mismo tipo que head (en su cláusula if). Puesto que también llama al fac en x (que a su vez llama a mod) infiere que x es también un tipo de clase Integral. En consecuencia, el compilador infiere el tipo

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> [a] -> a 

que lleva algún head -como número entero y como argumento ... que es poco probable que sea una cosa real.

Creo que el hecho de que pueda cargar ese código en GHCi es más una peculiaridad del intérprete. Si solo estuvieras compilando el código anterior, fallaría.

Editar: Supongo que el problema es que el verificador de tipos puede darle sentido a su código, sin embargo, probablemente no haya una forma sensata de usarlo.

+0

En realidad podría compilar (Mi versión es 7.2.1) :(¿Es esto un error en GHC ahora? Me pregunto ... Pero aún así, ¡gracias! –

+0

@ZiyaoWei no si intentas agregar esas declaraciones de tipo inferido. – soulcheck

+4

@ZiyaoWei : No es un error. GHC no puede saber que nunca habrá una función '[a] -> a' que sea una instancia de' Integral'. – leftaroundabout

11

Como se ha notado correctamente, el uso de la función fac interior de maxFactor añade una restricción Integral a del tipo de x. Por lo tanto, x debe ser del tipo Integral a => a.

Además, el compilador ve que maxFactor o bien devuelve head, que tiene escriba [a]->a o x. Por lo tanto x debe tener el tipo más específico Integral ([a]->a) => ([a]->a), y así maxFactor tiene por tipo

maxFactor :: Integral ([a] -> a) => ([a] -> a) -> ([a] -> a) 

que es exactamente lo que tienes. No hay nada "incorrecto" con esta definición hasta el momento. Si logró escribir una instancia de Integral tipo ([a]->a), puede invocar maxFactor sin problema. (Obviamente maxFactor no funcionaría como se esperaba.)

Cuestiones relacionadas