2012-02-28 10 views
5

el tipo de programa siguientes comprueba si puedo especificar en la línea de comandos (por ejemplo ghci file.hs):ghci - compilación ansiosa en modo interactivo?

import Data.Ratio 
foo = let x = [1..] 
      y = (1%2) + (head x) 
     in y 

Sin embargo, si entro de forma interactiva Voy a buscar un error de tipo:

Prelude> import Data.Ratio 
Prelude Data.Ratio> let x = [1..] 
Prelude Data.Ratio> let y = (1%2) + (head x) 
<interactive>:1:23: 
    Couldn't match expected type `Ratio a0' with actual type `Integer' 

Se parece que x se está escribiendo ansiosamente como [Integer] en comparación con el (Num t, Enum t) => [t] más general.

¿Hay algo que pueda hacer al respecto? ¿Hay otras situaciones en las que el modo interactivo difiera del modo por lotes?

+1

monomorphism restricción ... – augustss

+1

y escriba el impago – Ptival

+3

De hecho, es la restricción monomorphism temida. Hay dos formas de evitarlo: dar firma explícita o desactivar esta restricción (en GHCi, puede hacer ': set -XNoMonomorphismRestriction' y ya está; los pragmas de idioma y los indicadores de compilación también funcionan). – Vitus

Respuesta

10

enlaces sin argumentos, es decir, los de la forma x = ... están sujetos a el monomorphism restriction, lo que significa que GHC intentará hacerlo no polimórfico utilizando cualquier tipo de información disponible, y recurriendo al type defaulting para resolver cualquier amb Iguidades (En realidad, GHCi usa a slightly more permissive set of defaulting rules, pero eso realmente no importa para esta pregunta).

Dado que no hay otro tipo de información disponible cuando escribe let x = [1..], escriba el valor predeterminado provoca que el tipo se infiera como [Integer], ya que Integer es el tipo numérico predeterminado.

Hay varias maneras de resolver este problema:

  1. utilizar una firma tipo. Esto siempre funciona, pero a veces puede ser tedioso cuando se trabaja con tipos complejos.

    > let x = [1..] :: [Rational] 
    
  2. Escribir la unión con argumentos. Esto no se aplica en su caso, pero a veces ve este problema al escribir definiciones de funciones sin puntos.

    > let f = (+) 
    > :t f 
    f :: Integer -> Integer -> Integer 
    > let f x y = x + y 
    > :t f 
    f :: Num a => a -> a -> a 
    
  3. Dale el tipo corrector más información. En su caso, podríamos evitar el problema escribiendo ambos enlaces en una sola declaración let. GHC puede usar la información de tipo del segundo enlace para inferir correctamente que x debe tener el tipo [Rational].

    > let x = [1..]; y = 1%2 + head x 
    > :t x 
    x :: [Ratio Integer] 
    
  4. deshabilitar la restricción monomorphism. Esto puede tener graves implicaciones de rendimiento si esperaba que el tipo de algo sea, p. Ej. un Integer, mientras que en realidad es un Num a => a, ya que este último se debe volver a calcular cada vez que el primero se puede compartir. Esta es la razón principal por la cual existe la restricción en primer lugar.

    Sin embargo, en el caso del intérprete esto suele ser un problema menor, por lo que la conveniencia a menudo vale la pena.

    > :set -XNoMonomorphismRestriction 
    > let x = [1..] 
    > :t x 
    x :: (Num t, Enum t) => [t] 
    

    Si desea que esta activada de forma predeterminada, puede añadirlo a su .ghci file.

4

Usted puede hacer algo al respecto mediante la definición de x a ser las siguientes:

let x = [1..] :: [Ratio Int] 

como en:

Data.Ratio Prelude> let x = [1..] :: [Ratio Int] 
Data.Ratio Prelude> let y = (1%2) + (head x) 
Data.Ratio Prelude> y 
3 % 2 
Data.Ratio Prelude> 
+1

Recomiendo encarecidamente no utilizar 'Ratio Int', a menos que sepa absolutamente que su cálculo no puede desbordarse y está desesperado por el rendimiento, y aun así no me gusta. En mi opinión, fue un mal error hacer de 'Ratio' un tipo polimórfico, incluso los cálculos pequeños pueden exceder fácilmente los 64 bits, y entonces se obtiene un completo sinsentido. –

Cuestiones relacionadas