usar - ¿Por qué los valores polimórficos no se infieren en Haskell?
inferencia haskell (2)
Es la restricción de monomorfismo que dice que todos los valores, que se definen sin parámetros y no tienen una anotación de tipo explícito, deben tener un tipo monomórfico. Esta restricción se puede desactivar en ghc y ghci utilizando -XNoMonomorphismRestriction
.
El motivo de la restricción es que sin esta restricción long_calculation 42
se evaluaría dos veces, mientras que la mayoría de la gente probablemente esperaría / querría que solo se evaluara una vez:
longCalculation :: Num a => a -> a
longCalculation = ...
x = longCalculation 42
main = print $ x + x
Los literales numéricos tienen un tipo polimórfico:
*Main> :t 3
3 :: (Num t) => t
Pero si enlace una variable a tal literal, el polimorfismo se pierde:
x = 3
...
*Main> :t x
x :: Integer
Si defino una función, por otro lado, es por supuesto polimórfica:
f x = 3
...
*Main> :t f
f :: (Num t1) => t -> t1
Podría proporcionar una firma de tipo para asegurar que la x
permanezca 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?
Para expandir la respuesta de sepp2k un poco: si tratas de compilar lo siguiente (o lo cargas en GHCi), obtienes un error:
import Data.List (sort)
f = head . sort
Esto es una violación de la restricción de monomorfismo porque tenemos una restricción de clase (introducida por sort
) pero no argumentos explícitos: se nos dice (algo misteriosamente) que tenemos una Ambiguous type variable
en la restricción Ord a
.
Su ejemplo ( let x = 3
) tiene una variable de tipo similarmente ambigua, pero no da el mismo error porque las reglas de "default" de Haskell lo guardan:
Cualquier variable de tipo monomórfico que permanezca cuando se complete la inferencia de tipo para un módulo completo se considera ambigua y se resuelve a tipos particulares utilizando las reglas de incumplimiento (Sección 4.3.4).
Consulte esta respuesta para obtener más información acerca de las reglas de incumplimiento: 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
termine siendo un Int
lugar de un Integer
, y y = 3.0
sea un Rational
lugar de un Double
, puede usar una "declaración predeterminada" para anular las reglas predeterminadas predeterminadas :
default (Int, Rational)