Haskell Language
Aritmetisk
Sök…
Introduktion
I Haskell har alla uttryck (som inkluderar numeriska konstanter och funktioner som fungerar på dessa) en avgörbar typ. Vid sammanställningstid anger typkontrollen typen av ett uttryck från de typer av elementära funktioner som komponerar det. Eftersom data som standard inte kan ändras, finns det inga "typgjutning" -operationer, men det finns funktioner som kopierar data och generaliserar eller specialiserar typerna med anledning.
Anmärkningar
Den numeriska typklasshierarkin
Num
sitter vid roten till den numeriska typklasshierarkin. Dess karakteristiska operationer och några vanliga instanser visas nedan (de som laddas som standard med Prelude plus de för 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’
Vi har redan sett Fractional
, som kräver Num
och introducerar uppfattningarna om "delning" (/)
och ömsesidighet för ett nummer:
λ> :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’
De Real
klass modeller .. de reella tal. Det kräver Num
och Ord
, därför modellerar det ett ordnat numeriskt fält. Som ett motexempel är komplexa nummer inte ett ordnat fält (dvs. att de inte har ett naturligt beställningsförhållande):
λ> :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
representerar nummer som kan avrundas
λ> :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
(vilket innebär Fractional
) representerar konstanter och operationer som kanske inte har en begränsad decimalutvidgning.
λ> :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’
Varning: medan uttryck som sqrt . negate :: Floating a => a -> a
är perfekt giltiga, de kan returnera NaN
("inte-ett-nummer"), vilket kanske inte är ett avsedd beteende. I sådana fall kanske vi vill arbeta över Complex-fältet (visas senare).
Grundläggande exempel
λ> :t 1
1 :: Num t => t
λ> :t pi
pi :: Floating a => a
I exemplen ovan, de typ-checker härlett en typ- klass snarare än en konkret typ för de två konstanter. I Haskell är Num
klassen den mest generella numeriska klassen (eftersom den omfattar heltal och realer), men pi
måste tillhöra en mer specialiserad klass, eftersom den har en del som inte har en del.
list0 :: [Integer]
list0 = [1, 2, 3]
list1 :: [Double]
list1 = [1, 2, pi]
Betongtyperna ovan sluts av GHC. Mer generella typer som list0 :: Num a => [a]
skulle ha fungerat, men skulle också ha varit svårare att bevara (t.ex. om man gick med på en Double
på en lista med Num
), på grund av varningarna som visas ovan.
"Kunde inte härleda (Fraktionella int) ..."
Felmeddelandet i titeln är ett vanligt nybörjarfel. Låt oss se hur det uppstår och hur man fixar det.
Anta att vi måste beräkna medelvärdet för en lista med siffror; följande förklaring verkar göra det, men det skulle inte sammanställas:
averageOfList ll = sum ll / length ll
Problemet är med divisionen (/)
-funktionen: dess signatur är (/) :: Fractional a => a -> a -> a
, men i fallet ovanför nämnaren (ges av length :: Foldable t => ta -> Int
) är av typen Int
(och Int
tillhör inte Fractional
) därmed felmeddelandet.
Vi kan fixa felmeddelandet med fromIntegral :: (Num b, Integral a) => a -> b
. Man kan se att den här funktionen accepterar värden av alla Integral
typer och returnerar motsvarande i Num
klassen:
averageOfList' :: (Foldable t, Fractional a) => t a -> a
averageOfList' ll = sum ll / fromIntegral (length ll)
Funktionsexempel
Vad är typen av (+)
?
λ> :t (+)
(+) :: Num a => a -> a -> a
Vilken typ av sqrt
?
λ> :t sqrt
sqrt :: Floating a => a -> a
Vad är typen av sqrt . fromIntegral
?
sqrt . fromIntegral :: (Integral a, Floating c) => a -> c