22

literales numéricos tienen un tipo polimórfico:¿Por qué los valores polimórficos no se infieren en Haskell?

*Main> :t 3 
3 :: (Num t) => t 

Pero si Ato una variable a un tal literal, el polimorfismo se pierde:

x = 3 
... 
*Main> :t x 
x :: Integer 

Si defino una función, por el contrario, por supuesto es polimórfico:

f x = 3 
... 
*Main> :t f 
f :: (Num t1) => t -> t1 

pude proporcionar una declaración de tipo para garantizar la x queda polimórfica:

x :: Num a => a 
x = 3 
... 
*Main> :t x 
x :: (Num a) => a 

¿Pero por qué es esto necesario? ¿Por qué no se deduce el tipo polimórfico?

+0

¿Haría alguna diferencia? (Realmente no lo sé, aunque sospecho que no) – delnan

+3

Hace la diferencia; Quiero que el tipo sea lo más general posible. –

+0

Ven de nuevo? No importa si 'x' es' Integer' o 'Num a => a', puede pasarlo a cualquier función que espere un' Num'. Las funciones tienen que ser genéricas, los valores no. – delnan

Respuesta

24

Es el monomorphism restriction que dice que todos los valores, que se definen sin parámetros y no tienen una anotación de tipo explícita, deben tener un tipo monomórfico. Esta restricción se puede desactivar en ghc y ghci usando -XNoMonomorphismRestriction.

La razón de la restricción es que sin esta restricción long_calculation 42 sería evaluado dos veces, mientras que la mayoría de la gente probablemente esperaría/querer que sólo puede ser evaluado una vez:

longCalculation :: Num a => a -> a 
longCalculation = ... 

x = longCalculation 42 

main = print $ x + x 
+0

Ah, sí, la temida restricción del monomorfismo ... He oído hablar de esto, pero nunca he investigado qué era exactamente. ¡Gracias! –

+0

Si agregué las firmas de tipo explícitas a esto, ¿se seguiría evaluando dos veces, sin la extensión de restricción de monomorfismo? –

+0

@JustinL Si tiene un tipo polimórfico, se evaluará dos veces. Si tiene un tipo monomórfico, no lo hará. La restricción de monomorfismo solo afecta si obtendrá un tipo monomórfico o polimórfico sin anotaciones. Si agrega anotaciones, la restricción de monomorfismo no hace diferencia. – sepp2k

20

Para ampliar la respuesta de sepp2k un poco: si intenta compilar el siguiente (o cargarlo en GHCi), se obtiene un error:

import Data.List (sort) 
f = head . sort 

Ésta es una violación de la restricción monomorphism porque tenemos una restricción de clase (introducido por sort), pero no ex argumentos explícitos: se nos dice (algo misteriosamente) que tenemos un Ambiguous type variable en la restricción Ord a.

Su ejemplo (let x = 3) tiene una variable de tipo similarmente ambiguo, pero no da el mismo error, porque es salvado por Haskell's "defaulting" rules:

Any monomorphic type variables that remain when type inference for an entire module is complete, are considered ambiguous, and are resolved to particular types using the defaulting rules (Section 4.3.4).

Ver this answer para obtener más información sobre los morosos reglas -la El punto importante es que solo funcionan para ciertas clases numéricas, por lo que x = 3 está bien, mientras que f = sort no.

Como nota al margen: si prefiere que x = 3 terminan siendo un Int en lugar de un Integer y y = 3.0 ser un Rational en lugar de un Double, se puede utilizar una "declaración de default" para anular el valor predeterminado morosos reglas :

default (Int, Rational) 
+0

+1, excelente complemento a la respuesta de sepp2k –

+1

Cuando coloco 'f = head. sort' en un archivo e intento cargarlo, obtengo un error, pero cuando escribo' let f = head. sort' en GHCi no obtengo ningún error, y el El enlace resultante tiene este tipo: 'f :: [()] ->()'. ¿Qué pasa con eso? –

+2

@pelotom: Se debe a las [reglas predeterminadas extendidas] de GHCi (http://www.haskell.org/ ghc/docs/6.12.2/html/users_guide/interactive-evaluation.html # extended-default-rules). –

Cuestiones relacionadas