Haskell Language
Arithmetik
Suche…
Einführung
In Haskell haben alle Ausdrücke (einschließlich numerischer Konstanten und Funktionen, die auf diese angewendet werden) einen entscheidbaren Typ. Bei der Kompilierung entnimmt der Typprüfer den Typ eines Ausdrucks aus den Typen der Elementarfunktionen, aus denen er besteht. Da Daten standardmäßig unveränderlich sind, gibt es keine "Typumwandlung" -Operationen, aber es gibt Funktionen, die Daten kopieren und die Typen innerhalb eines bestimmten Grunds generalisieren oder spezialisieren.
Bemerkungen
Die numerische Typenklassenhierarchie
Num
befindet sich am Stamm der numerischen Typenklassenhierarchie. Seine charakteristischen Operationen und einige häufige Instanzen werden unten gezeigt (die standardmäßig mit Prelude geladenen und die von 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’
Wir haben bereits die Fractional
Klasse gesehen, die Num
benötigt und die Begriffe "Division" (/)
und Kehrwert einer Zahl einführt:
λ> :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’
Die Real
Klasse-Modelle .. die reellen Zahlen. Es erfordert Num
und Ord
, daher modelliert es ein geordnetes numerisches Feld. Als Gegenbeispiel sind komplexe Zahlen kein geordnetes Feld (dh sie besitzen keine natürliche Ordnungsbeziehung):
λ> :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
für Zahlen, die gerundet werden können
λ> :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
(was " Fractional
) steht für Konstanten und Operationen, die möglicherweise keine endliche dezimale Erweiterung haben.
λ> :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’
Achtung: Während Ausdrücke wie sqrt . negate :: Floating a => a -> a
sind absolut gültig, sie können NaN
("not-a-number") zurückgeben, was möglicherweise nicht beabsichtigt ist. In solchen Fällen möchten wir möglicherweise das Feld "Komplex" (später angezeigt) bearbeiten.
Grundlegende Beispiele
λ> :t 1
1 :: Num t => t
λ> :t pi
pi :: Floating a => a
In den obigen Beispielen, folgert die Typprüfung eine Typ- Klasse anstatt einen konkreten Typ für die beiden Konstanten. In Haskell ist die Num
Klasse die allgemeinste numerische (da sie ganze und reelle Zahlen umfasst), aber pi
muss zu einer spezialisierteren Klasse gehören, da es einen gebrochenen Anteil ungleich Null hat.
list0 :: [Integer]
list0 = [1, 2, 3]
list1 :: [Double]
list1 = [1, 2, pi]
Die konkreten Typen wurden von GHC abgeleitet. Allgemeinere Typen wie list0 :: Num a => [a]
hätten funktioniert, wären aber aufgrund der oben aufgeführten Vorbehalte auch schwieriger zu erhalten (z. B. wenn ein Double
auf einer Liste von Num
s verbraucht wurde).
"Konnte nicht ableiten (Fractional Int) ..."
Die Fehlermeldung im Titel ist ein häufiger Anfängerfehler. Mal sehen, wie es entsteht und wie man es beheben kann.
Angenommen, wir müssen den Durchschnittswert einer Liste von Zahlen berechnen. Die folgende Deklaration scheint das zu tun, würde aber nicht kompilieren:
averageOfList ll = sum ll / length ll
Das Problem liegt bei der Funktion division (/)
: Die Signatur lautet (/) :: Fractional a => a -> a -> a
, aber im Fall über dem Nenner (gegeben durch length :: Foldable t => ta -> Int
) ist vom Typ Int
(und Int
gehört nicht zur Klasse Fractional
), daher die Fehlermeldung.
Wir können die Fehlermeldung mit fromIntegral :: (Num b, Integral a) => a -> b
beheben. Man kann sehen, dass diese Funktion Werte eines beliebigen Integral
akzeptiert und entsprechende Werte in der Klasse Num
zurückgibt:
averageOfList' :: (Foldable t, Fractional a) => t a -> a
averageOfList' ll = sum ll / fromIntegral (length ll)
Funktionsbeispiele
Was ist der Typ von (+)
?
λ> :t (+)
(+) :: Num a => a -> a -> a
Was ist der Typ von sqrt
?
λ> :t sqrt
sqrt :: Floating a => a -> a
Was ist der Typ von sqrt . fromIntegral
?
sqrt . fromIntegral :: (Integral a, Floating c) => a -> c