2012-04-17 8 views
8

Observe la segunda línea en esta sesión de GHCi. ¿De qué se trata el tipo de Latitude que me permite usar un número "vacío" como valor, en lugar de tener que invocar un constructor? Me gustaría hacer algo similar con algunos de mis propios tipos.Asignación de números "descubiertos" a newtypes

λ> :m + Data.Geo.GPX.Type.Latitude                         
λ> let t = 45 :: Latitude                            
λ> t                                 
45.0 

He examinado el código fuente para el tipo de Latitude, pero tuve problemas para resolverlo al principio. Eventualmente encontré la respuesta, así que pensé en documentarla aquí. Ver mi respuesta a continuación.

Respuesta

4

De acuerdo con el estándar Haskell98, los literales numéricos son en realidad llamadas a fromInteger y fromRational. Esto les permite convertirse a cualquier tipo que implemente esas funciones (fromInteger está en la clase de tipo Prelude.Num y fromRational está en la clase de tipos Prelude.Fractional).

La sintaxis de los literales numéricos se proporciona en la Sección 2.5. Un número entero literal representa la aplicación de la función fromInteger al valor apropiado de tipo Integer. De forma similar, un literal flotante representa una aplicación de fromRational a un valor de tipo Rational (es decir, Ratio Integer). Dadas las tipificaciones:

fromInteger :: (Num a) => Integer -> un

fromRational :: (Fractional a) => racionales -> un número entero

y literales flotantes tienen las tipificaciones (Num a) => a y (fraccional a) => a, respectivamente. Los literales numéricos se definen en de esta manera indirecta para que puedan interpretarse como valores de cualquier tipo numérico apropiado . Vea la Sección 4.3.4 para una discusión de sobrecarga de ambigüedad.

http://www.haskell.org/onlinereport/basic.html#numeric-literals

6

Lo que hace que esto funcione es que el tipo es un Num. La forma más fácil de hacerlo es usar "derivando Num", en cuyo caso necesito el lenguaje pragma GeneralizedNewtypeDeriving. Así que se puede crear un tipo como el siguiente,

newtype Seconds = Seconds Double deriving (Eq, Ord, Enum, Num, Fractional, Floating, Real, RealFrac, RealFloat, Show) 

Y luego, en GHCi,

λ> let s = 5 :: Seconds                            
λ> s                                 
Seconds 5.0 

Alternativamente, pude poner en práctica de manera explícita Num.

+4

Para ser exactos, es el hecho de que 'Seconds' está en la clase' Num' que hace que funcione. No importa cómo se convirtió en miembro de la clase 'Num'. – augustss

+2

También funcionaría si la instancia se proporcionara explícitamente en lugar de derivada. Todo lo que necesitas es un 'instance Num'. –

+0

Gracias augustss y Daniel. He actualizado la respuesta. – mhwombat

Cuestiones relacionadas