Buscar..


Introducción

En Haskell, todas las expresiones (que incluyen las constantes numéricas y las funciones que operan en ellas) tienen un tipo decidible. En el momento de la compilación, el comprobador de tipos infiere el tipo de una expresión de los tipos de funciones elementales que la componen. Dado que los datos son inmutables de manera predeterminada, no hay operaciones de "conversión de tipo", pero hay funciones que copian los datos y generalizan o especializan los tipos dentro de la razón.

Observaciones

La jerarquía de clases de tipo numérico.

Num encuentra en la raíz de la jerarquía de clases de tipo numérica. A continuación se muestran sus operaciones características y algunas instancias comunes (las cargadas de forma predeterminada con Prelude más las de Data.Complex ):

λ> :i Num
class Num a where
  (+) :: a -> a -> a
  (-) :: a -> a -> a
  (*) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a
  {-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-}
      -- Defined in ‘GHC.Num’
instance RealFloat a => Num (Complex a) -- Defined in ‘Data.Complex’
instance Num Word -- Defined in ‘GHC.Num’
instance Num Integer -- Defined in ‘GHC.Num’
instance Num Int -- Defined in ‘GHC.Num’
instance Num Float -- Defined in ‘GHC.Float’
instance Num Double -- Defined in ‘GHC.Float’

Ya hemos visto la clase Fractional , que requiere Num e introduce las nociones de "división" (/) y recíproco de un número:

λ> :i Fractional
class Num a => Fractional a where
  (/) :: a -> a -> a
  recip :: a -> a
  fromRational :: Rational -> a
  {-# MINIMAL fromRational, (recip | (/)) #-}
      -- Defined in ‘GHC.Real’
instance RealFloat a => Fractional (Complex a) -- Defined in ‘Data.Complex’
instance Fractional Float -- Defined in ‘GHC.Float’
instance Fractional Double -- Defined in ‘GHC.Float’

La clase Real modela ... los números reales. Requiere Num y Ord , por lo tanto, modela un campo numérico ordenado. Como contraejemplo, los números complejos no son un campo ordenado (es decir, no poseen una relación de orden natural):

λ> :i Real
class (Num a, Ord a) => Real a where
  toRational :: a -> Rational
  {-# MINIMAL toRational #-}
      -- Defined in ‘GHC.Real’
instance Real Word -- Defined in ‘GHC.Real’
instance Real Integer -- Defined in ‘GHC.Real’
instance Real Int -- Defined in ‘GHC.Real’
instance Real Float -- Defined in ‘GHC.Float’
instance Real Double -- Defined in ‘GHC.Float’

RealFrac representa números que pueden ser redondeados

λ> :i RealFrac
class (Real a, Fractional a) => RealFrac a where
  properFraction :: Integral b => a -> (b, a)
  truncate :: Integral b => a -> b
  round :: Integral b => a -> b
  ceiling :: Integral b => a -> b
  floor :: Integral b => a -> b
  {-# MINIMAL properFraction #-}
      -- Defined in ‘GHC.Real’
instance RealFrac Float -- Defined in ‘GHC.Float’
instance RealFrac Double -- Defined in ‘GHC.Float’

Floating (lo que implica Fractional ) representa constantes y operaciones que pueden no tener una expansión decimal finita.

λ> :i Floating
class Fractional a => Floating a where
  pi :: a
  exp :: a -> a
  log :: a -> a
  sqrt :: a -> a
  (**) :: a -> a -> a
  logBase :: a -> a -> a
  sin :: a -> a
  cos :: a -> a
  tan :: a -> a
  asin :: a -> a
  acos :: a -> a
  atan :: a -> a
  sinh :: a -> a
  cosh :: a -> a
  tanh :: a -> a
  asinh :: a -> a
  acosh :: a -> a
  atanh :: a -> a
  GHC.Float.log1p :: a -> a
  GHC.Float.expm1 :: a -> a
  GHC.Float.log1pexp :: a -> a
  GHC.Float.log1mexp :: a -> a
  {-# MINIMAL pi, exp, log, sin, cos, asin, acos, atan, sinh, cosh,
              asinh, acosh, atanh #-}
      -- Defined in ‘GHC.Float’
instance RealFloat a => Floating (Complex a) -- Defined in ‘Data.Complex’
instance Floating Float -- Defined in ‘GHC.Float’
instance Floating Double -- Defined in ‘GHC.Float’

Precaución: mientras que expresiones como sqrt . negate :: Floating a => a -> a son perfectamente válidos, pueden devolver NaN ("no-a-number"), que puede no ser un comportamiento intencionado. En tales casos, podríamos querer trabajar sobre el campo Complejo (se muestra más adelante).

Ejemplos basicos

λ> :t 1
1 :: Num t => t

λ> :t pi
pi :: Floating a => a

En los ejemplos anteriores, el comprobador de tipos infiere una clase de tipo en lugar de un tipo concreto para las dos constantes. En Haskell, la clase Num es la más numérica general (ya que abarca números enteros y reales), pero pi debe pertenecer a una clase más especializada, ya que tiene una parte fraccionaria distinta de cero.

list0 :: [Integer]
list0 = [1, 2, 3]

list1 :: [Double]
list1 = [1, 2, pi]

Los tipos de hormigón anteriores fueron inferidos por GHC. Tipos más generales como list0 :: Num a => [a] habrían funcionado, pero también hubieran sido más difíciles de conservar (por ejemplo, si uno considera un Double en una lista de Num s), debido a las advertencias que se muestran arriba.

`No se pudo deducir (Fraccional Int) ...`

El mensaje de error en el título es un error común de principiante. Veamos cómo surge y cómo solucionarlo.

Supongamos que necesitamos calcular el valor promedio de una lista de números; La siguiente declaración parecería hacerlo, pero no compilaría:

averageOfList ll = sum ll / length ll

El problema es con la función de división (/) : su firma es (/) :: Fractional a => a -> a -> a , pero en el caso sobre el denominador (dado por length :: Foldable t => ta -> Int ) es de tipo Int (y Int no pertenece a la clase Fractional ) de ahí el mensaje de error.

Podemos corregir el mensaje de error con fromIntegral :: (Num b, Integral a) => a -> b . Se puede ver que esta función acepta valores de cualquier tipo Integral y devuelve los correspondientes en la clase Num :

averageOfList' :: (Foldable t, Fractional a) => t a -> a
averageOfList' ll = sum ll / fromIntegral (length ll)

Ejemplos de funciones

¿Cuál es el tipo de (+) ?

λ> :t (+)
(+) :: Num a => a -> a -> a

¿Cuál es el tipo de sqrt ?

λ> :t sqrt
sqrt :: Floating a => a -> a

¿Cuál es el tipo de sqrt . fromIntegral ?

sqrt . fromIntegral :: (Integral a, Floating c) => a -> c


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow