Haskell Language
арифметика
Поиск…
Вступление
В Haskell все выражения (включая числовые константы и функции, действующие на них) имеют разрешимый тип. Во время компиляции тип-checker определяет тип выражения из типов элементарных функций, которые его составляют. Так как данные по умолчанию неизменяемы, то нет операций типа «casting», но есть функции, которые копируют данные и обобщают или специализируют типы в пределах причины.
замечания
Числовая иерархия типов
Num
сидит в корневой строке иерархии типов. Его характерные операции и некоторые общие примеры показаны ниже (те, которые загружаются по умолчанию с Prelude плюс те, что у 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’
Мы уже видели класс Fractional
, который требует Num
и вводит понятия «деления» (/)
и обратного числа:
λ> :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’
Real
классы моделей .. действительные числа. Он требует Num
и Ord
, поэтому он моделирует упорядоченное числовое поле. В качестве контрпримера комплексные числа не являются упорядоченным полем (т. Е. Не имеют естественного отношения упорядочения):
λ> :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
представляет числа, которые могут быть округлены
λ> :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
(что подразумевает Fractional
) представляет собой константы и операции, которые могут не иметь конечного десятичного разложения.
λ> :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’
Внимание: в то время как выражения, такие как sqrt . negate :: Floating a => a -> a
абсолютно верны, они могут возвращать NaN
(«не-число»), что может быть не предполагаемым поведением. В таких случаях мы, возможно, захотим работать над полем Комплекс (показано ниже).
Основные примеры
λ> :t 1
1 :: Num t => t
λ> :t pi
pi :: Floating a => a
В приведенных выше примерах, типа проверка выводит типа вируса класса , а не конкретный типа для двух констант. В Haskell класс Num
является наиболее общим численным (поскольку он охватывает целые числа и числа), но pi
должен принадлежать к более специализированному классу, поскольку он имеет ненулевую дробную часть.
list0 :: [Integer]
list0 = [1, 2, 3]
list1 :: [Double]
list1 = [1, 2, pi]
Конкретные типы, указанные выше, были выведены GHC. Более общие типы, такие как list0 :: Num a => [a]
, сработали бы, но было бы еще сложнее сохранить (например, если бы один из них содержал Double
в списке Num
s) из-за описанных выше предостережений.
`Не удалось вывести (Fractional Int) ...`
Сообщение об ошибке в заголовке является общей ошибкой начинающего. Давайте посмотрим, как это происходит и как это исправить.
Предположим, нам нужно вычислить среднее значение списка чисел; следующее заявление, похоже, сделает это, но оно не будет компилироваться:
averageOfList ll = sum ll / length ll
Проблема заключается в функции деления (/)
: ее сигнатура есть (/) :: Fractional a => a -> a -> a
, но в случае выше знаменатель (заданный length :: Foldable t => ta -> Int
) имеет тип Int
(и Int
не принадлежит классу Fractional
), следовательно, сообщение об ошибке.
Мы можем исправить сообщение об ошибке с fromIntegral :: (Num b, Integral a) => a -> b
. Можно видеть, что эта функция принимает значения любого Integral
типа и возвращает соответствующие в классе Num
:
averageOfList' :: (Foldable t, Fractional a) => t a -> a
averageOfList' ll = sum ll / fromIntegral (length ll)
Примеры функций
Какой тип (+)
?
λ> :t (+)
(+) :: Num a => a -> a -> a
Какой тип sqrt
?
λ> :t sqrt
sqrt :: Floating a => a -> a
Каков тип sqrt . fromIntegral
?
sqrt . fromIntegral :: (Integral a, Floating c) => a -> c