Haskell - типизированный язык со строгой статической системой типов. Термин "строгий" означает, что отсутствует неявное приведение типов. Термин "статический" означает, что проверка типов происходит не во время исполнения, а во время компиляции. Haskell умеет выводить тип практически любого выражения самостоятельно. Если выражение правильно построено, то тогда его тип выводится, а если в выражении содержится какая-то ошибка, то тогда система вывода типов Haskell возвращает сообщение об ошибке.
Имена типов начинаются с большой буквы. Два двоеточия подряд - это оператор типизации в Haskell. Этот оператор связывает выражения, которые стоят слева от этого оператора с типами, которые стоят справа.
В Haskell имеется стандартный набор числовых типов:
В Haskell имеется стандартный набор числовых типов:
- Int - для целых ограниченного размера;
- Integer - для целых произвольного размера;
- Float - числа с плавающей точкой одинарной точности;
- Double - числа с плавающей точкой двойной точности.
Char
Тип Char является простейшим типом. Его населяют все символы алфавита, юникода и управляющие последовательности.
Prelude> :type 'c' 'c' :: Char Prelude> :type '\n' '\n' :: Char
Bool
Prelude> :type True True :: Bool Prelude> :t False False :: Bool
Num
Числовые константы без точки принадлежат классу типов Num.
Prelude> :t 3 3 :: Num a => a
Определение класса типов Num:
class Num a where (+), (-), (*) :: a -> a -> a negate :: a -> a -- унарный префиксный минус abs :: a -> a -- модуль числа signum :: a -> a -- знак числа fromInteger :: Integer -> a -- переход от значений типа Integer к любому числовому типу -- реализация по умолчанию: x - y = x + negate y negate x = 0 - x {- LAW abs x * signum x == x -}
На самом деле все численные константы, которые определены в языке, в реализации GHCi определены как представители типа Integer. И всегда когда мы их используем, они при трансляции заменяются на вызов функции fromInteger на некотором числе.
Prelude> fromInteger 3 3 Prelude> :t fromInteger 3 fromInteger 3 :: Num a => a
В Haskell иногда для классов типов формулируются законы. Компилятор эти законы не может проверять, но для того чтобы класс типов разумным образом можно было использовать выполнение этих законов требуется от программиста. Закон для класса типов Num такой, модуль числа умноженный на знак числа должен равняться самому числу.
Деление в классе типов Num не определено потому что деление для целых чисел и чисел с плавающей точкой реализовано совершенно по-разному.
У класса типов Num есть два расширения (наследника): класс типов Integral и Fractional. Класс типов Integral отвечает за целочисленное деление. Класс типов Fractional отвечает за деление типов с плавающей точкой.
Integral
Prelude> :i Integral class (Real a, Enum a) => Integral a where quot :: a -> a -> a rem :: a -> a -> a div :: a -> a -> a mod :: a -> a -> a quotRem :: a -> a -> (a, a) divMod :: a -> a -> (a, a) toInteger :: a -> Integer -- Defined in ‘GHC.Real’ instance Integral Word -- Defined in ‘GHC.Real’ instance Integral Integer -- Defined in ‘GHC.Real’ instance Integral Int -- Defined in ‘GHC.Real’
Real наследует Ord и Num. Основные функции целочисленного деления это div и mod. Есть дополнительная функция, которая называется divMod - она возвращает пару, т.е. она выполняет работу и div и mod одновременно. Функции quot и rem тоже выполняют целочисленное деление. Дело в том что целочисленное деление на отрицательных числах может быть определено двумя разными способами. Не вдаваясь в подробности, там возникает проблема со знаками. Функции div и mod это стандартное целочисленное деление. Функции quot и rem работают слегка эффективнее, но результат по знаку немножко отличается от div и mod. Функция toInteger приводит любой интегральный тип к типу Integer. Стандартные представители класса типов Integral это Integer и Int.
Следующая функция с сигнатурой avg :: Int -> Int -> Int -> Double вычисляет среднее значение переданных в нее аргументов.
avg a b c = (fromIntegral $ a + b + c) / 3.0
GHCi> avg 3 4 8 5.0
Fractional
Числовые константы с точкой принадлежат классу типов Fractional. К классу типов Fractional относятся типы Double и Float.
Prelude> :t 3.5 3.5 :: Fractional a => a
Fractional - это другая ветвь наследования от класса типов Num. Fractional определяет полноценное деление. К классу типов Fractional относятся Float и Double. Есть еще тип рациональных чисел в котором тоже полноценное деление определено. Тип рациональных чисел состоит из числителя и знаменателя. Функция fromRational преобразует тип рациональных чисел к типу Fractional.
Prelude> :i Fractional class Num a => Fractional a where (/) :: a -> a -> a recip :: a -> a fromRational :: Rational -> a -- Defined in ‘GHC.Real’ instance Fractional Float -- Defined in ‘GHC.Float’ instance Fractional Double -- Defined in ‘GHC.Float’
Floating
От класса типов Fractional наследуется класс типов Floating. В этом классе типов определена все стандартные математические функции.Prelude> :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 -- Defined in ‘GHC.Float’ instance Floating Float -- Defined in ‘GHC.Float’ instance Floating Double -- Defined in ‘GHC.Float’
RealFrac
RealFrac наследуется от Real и от Floating. Этот класс типов полезен тем, что он содержит целый набор функций связанных с округлением значений с плавающей точкой до целых типов. Функция truncate просто отбрасывает десятичную часть. Функция round, которая округляет, т.е. выбирает наиболее близкое значение интегрального типа. Функции ceiling и floor задают соответственно верхнюю и нижнюю целочисленную грань числа с плавающей точкой.Prelude> :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 -- Defined in ‘GHC.Real’ instance RealFrac Float -- Defined in ‘GHC.Float’ instance RealFrac Double -- Defined in ‘GHC.Float’
RealFloat
RealFloat - это довольно технический класс типов, который описывает внутреннее представление чисел с плавающей точкой. На самом деле числа с плавающей точкой внутри компьютера реализованы в виде мантиссы, экспоненты, основания... вот вся соответствующая информация о данном конкретном типе с плавающей точкой присутствует в классе RealFloat.Prelude> :i RealFloat class (RealFrac a, Floating a) => RealFloat a where floatRadix :: a -> Integer floatDigits :: a -> Int floatRange :: a -> (Int, Int) decodeFloat :: a -> (Integer, Int) encodeFloat :: Integer -> Int -> a exponent :: a -> Int significand :: a -> a scaleFloat :: Int -> a -> a isNaN :: a -> Bool isInfinite :: a -> Bool isDenormalized :: a -> Bool isNegativeZero :: a -> Bool isIEEE :: a -> Bool atan2 :: a -> a -> a -- Defined in ‘GHC.Float’ instance RealFloat Float -- Defined in ‘GHC.Float’ instance RealFloat Double -- Defined in ‘GHC.Float’
Int
Можно явно задать конкретный тип:Prelude> let x = 3 :: Int Prelude> x 3 Prelude> :type x x :: Int
Integer
Тип Integer может содержать константы произвольной длины.Prelude> 123456789123456789123456789123456789123456789123456789 :: Integer 123456789123456789123456789123456789123456789123456789
Double
Prelude> let y = 3 :: Double Prelude> y 3.0 Prelude> :t y y :: Double Prelude> let z = y + 17 Prelude> z 20.0 Prelude> :t z z :: Double
В реальных финансовых приложениях использовать тип с плавающей точкой для хранения подобной информации не рекомендуется.
Комментариев нет:
Отправить комментарий