ghci> read "5" :: Int
5
ghci> read "5" :: Float
5.0
ghci> (read "5" :: Float) * 4
20.0
ghci> read "[1,2,3,4]" :: [Int]
[1,2,3,4]
ghci> read "(3, 'a')" :: (Int, Char)
(3, 'a')
Для большинства выражений компилятор может вывести тип самостоятельно. Но иногда он не знает, вернуть ли значение типа Int
или Float
для выражения вроде read "5"
. Чтобы узнать, какой у него тип, язык Haskell должен был бы фактически вычислить read "5"
.
Но так как Haskell – статически типизированный язык, он должен знать все типы до того, как скомпилируется код (или, в случае GHCi, вычислится). Так что мы должны сказать языку: «Эй, это выражение должно иметь вот такой тип, если ты сам случайно не понял!»
Обычно компилятору достаточно минимума информации, чтобы определить, значение какого именно типа должна вернуть функция read
. Скажем, если результат функции read
помещается в список, то Haskell использует тип списка, полученный благодаря наличию других элементов списка:
ghci> [read "True" , False, True, False]
[True, False, True, False]
Так как read
"True"
используется как элемент списка булевых значений, Haskell самостоятельно определяет, что тип read "True"
должен быть Bool
.
Класс Enum
Экземплярами класса Enum
являются последовательно упорядоченные типы; их значения можно перенумеровать. Основное преимущество класса типов Enum
в том, что мы можем использовать его типы в интервалах списков. Кроме того, у них есть предыдущие и последующие элементы, которые можно получить с помощью функций succ
и pred
. Типы, входящие в этот класс: ()
, Bool
, Char
, Ordering
, Int
, Integer
, Float
и Double
.
ghci> ['a'..'e']
"abcde"
ghci> [LT .. GT]
[LT,EQ,GT]
ghci> [3 .. 5]
[3,4,5]
ghci>succ 'B'
'C'
Класс Bounded
Экземпляры класса типов Bounded
имеют верхнюю и нижнюю границу.
ghci> minBound :: Int
–2147483648
ghci> maxBound :: Char
'\1114111'
ghci> maxBound :: Bool
True
ghci> minBound :: Bool
False
Функции minBound
и maxBound
интересны тем, что имеют тип (Bounded a) => a
. В этом смысле они являются полиморфными константами.
Все кортежи также являются частью класса Bounded
, если их компоненты принадлежат классу Bounded
.
ghci> maxBound :: (Bool, Int, Char)
(True,2147483647,'\1114111')
Класс Num
Класс Num
– это класс типов для чисел. Его экземпляры могут вести себя как числа. Давайте проверим тип некоторого числа:
ghci> :t 20
20 :: (Num t) => t
Похоже, что все числа также являются полиморфными константами. Они могут вести себя как любой тип, являющийся экземпляром класса Num
(Int
, Integer
, Float
или Double
).
ghci> 20 :: Int
20
ghci> 20 :: Integer
20
ghci> 20 :: Float
20.0
ghci> 20 :: Double
20.0
Если проверить тип оператора *
, можно увидеть, что он принимает любые числа.
ghci> :t (*)
(*) :: (Num a) => a –> a –> a
Он принимает два числа одинакового типа и возвращает число этого же типа. Именно поэтому (5 :: Int) * (6 :: Integer)
приведёт к ошибке, а 5 * (6 :: Integer)
будет работать нормально и вернёт значение типа Integer
потому, что 5 может вести себя и как Integer
, и как Int
.
Чтобы присоединиться к классу Num
, тип должен «подружиться» с классами Show
и Eq
.
Класс Floating
Класс Floating
включает в себя только числа с плавающей точкой, то есть типы Float
и Double
.
Функции, которые принимают и возвращают значения, являющиеся экземплярами класса Floating
, требуют, чтобы эти значения могли быть представлены в виде числа с плавающей точкой для выполнения осмысленных вычислений. Некоторые примеры: функции sin
, cos
и sqrt
.
Класс Integral
Класс Integral
– тоже числовой класс типов. Если класс Num
включает в себя все типы, в том числе действительные и целые числа, то в класс Integral
входят только целые числа. Для типов Int
и Integer
определены экземпляры данного класса.