функция fromInteger, а если 2.0, то будет применена функция fromRational.
Стандартные числа
В этом подразделе мы рассмотрим несколько стандартных типов для чисел в Haskell. Все эти числа явля-
ются экземплярами основных численных классов. Тех, которые мы рассмотрели, и многих-многих других.
Целые числа
В Haskell предусмотрено два типа для целых чисел. Это Integer
и Int. Чем они отличаются? Значениятипа Integer
не ограничены, мы можем проводить вычисления с очень-очень-очень большими числами, еслипамяти на нашем компьютере хватит. Числа из типа Int
ограничены. Каждое число занимает определённыйразмер в памяти компьютера. Диапазон значений для Int
составляет отболее эффективны.
Действительные числа
Действительные числа бывают дробными (тип Rational
), с ординарной точностью Float и с двойнойточностью Double
. Числа из типа Float занимают меньше места, но они не такие точные как Double. Если высомневаетесь, чем пользоваться, выбирайте Double
, обычно Float используется только там, где необходимохранить огромные массивы чисел. В этом случае мы экономим много памяти.
Преобразование численных типов
Во многих языках программирования при сложении или умножении чисел разных типов проводится ав-
томатическое приведение типов. Обычно целые числа становятся действительными, Float
превращается вDouble
и так далее. Это противоречит строгой типизации, поэтому в Haskell этого нет:Prelude>
(1::Int) + (1::Double)<
interactive>:2:13:Couldn’t
match expected type ‘Int’ with actual type ‘Double’In
the second argument of ‘(+)’, namely ‘(1 :: Double)’In
the expression: (1 :: Int) + (1 :: Double)In
an equation for ‘it’: it = (1 :: Int) + (1 :: Double)Любое преобразование типов контролируется пользователем. Мы должны вызвать специальную функ-
цию.
От целых к действительным:
Часто возникает необходимость приведения целых чисел к действитель-ным при делении. Для этого можно воспользоваться функцией: fromIntegral
Prelude> :
i fromIntegralfromIntegral ::
(Integral a, Num b) => a -> b-- Defined in ‘GHC.Real’
Определим функцию поиска среднего между двумя целыми числами:
meanInt :: Int -> Int -> Double
meanInt a b =
fromIntegral (a + b) / 2Арифметика | 35
В этой функции двойка имеет тип Double
. Обратите внимание на скобки: составной синоним всегда при-тягивает аргументы сильнее чем бинарная операция.
От действительных к целым:
В этом нам поможет класс RealFrac. Методы говорят сами за себя:Prelude GHC.Float> :
i RealFracclass
(Real a, Fractional a) => RealFrac a whereproperFraction :: Integral
b => a -> (b, a)truncate :: Integral
b => a -> bround :: Integral
b => a -> bceiling :: Integral
b => a -> bfloor :: Integral
b => a -> b-- Defined in ‘GHC.Real’
instance RealFrac Float
-- Defined in ‘GHC.Float’instance RealFrac Double
-- Defined in ‘GHC.Float’Метод properFraction отделяет целую часть числа от дробной:
properFraction :: Integral
b => a -> (b, a)Для того, чтобы вернуть сразу два значения используется кортеж (кортежи пишутся в обычных скобках,
значения следуют через запятую):
Prelude>
properFraction 2.5(2,0.5)
Для пар (кортеж, состоящий из двух элементов) определены две удобные функции извлечения элементов,
их смысл можно понять по одним лишь типам:
fst ::
(a, b) -> asnd ::
(a, b) -> bПроверим:
Prelude> let
x = properFraction 2.5Prelude>
(fst x, snd x)(2, 0.5)
Мы бы и сами могли определить такие функции:
fst ::
(a, b) -> afst (a, _
) = asnd ::
(a, b) -> bsnd (_
, b) = bМежду действительными числами:
Кто-то написал очень хорошую функцию, но она определена наDouble
, а вам приходится использовать Float. Как быть? Нам поможет функция realToFrac:Prelude> :
i realToFracrealToFrac ::
(Real a, Fractional b) => a -> b-- Defined in ‘GHC.Real’
Она принимает значение из класса Real
и приводит его к значению, которое можно делить. Что это закласс Real
? Математики наверное смекнут, что это противоположность комплексным числам (где-то долженбыть определён тип или класс Complex
, и он правда есть, но об этом в следующем разделе). При переходек комплексным числам мы теряем способность сравнения на больше/меньше, но сохраняем возможность
вычисления арифметических операций, поэтому класс Real
это пересечение классов Num и Ord:Prelude> :
i Realclass
(Num a, Ord a) => Real a wheretoRational ::
a -> RationalЗдесь “пересечение” означает “и тот и другой”. Пересечение классов кодируется с помощью контекста.
Вернёмся к нашему первому примеру:
36 | Глава 2: Первая программа