Параметры разделены символами –>, и здесь нет никакого различия между параметрами и типом возвращаемого значения. Возвращаемый тип – это последний элемент в объявлении, а параметры – первые три.
Позже мы увидим, почему они просто разделяются с помощью символов –>
, вместо того чтобы тип возвращаемого значения как-то специально отделялся от типов параметров (например, Int, Int, Int –> Int
или что-то в этом духе).
Если вы хотите объявить тип вашей функции, но не уверены, каким он должен быть, то всегда можно написать функцию без него, а затем проверить тип с помощью :t
. Функции – тоже выражения, так что :t
будет работать с ними без проблем.
Обычные типы в языке Haskell
А вот обзор некоторых часто используемых типов.
• Тип Int
обозначает целое число. Число 7 может быть типа Int
, но 7.2 – нет. Тип Int
ограничен: у него есть минимальное и максимальное значения. Обычно на 32-битных машинах максимально возможное значение типа Int
– это 2 147 483 647, а минимально возможное – соответственно, –2 147 483 648.
ПРИМЕЧАНИЕ. Мы используем компилятор GHC, в котором множество возможных значений типа Int определено размером машинного слова на используемом компьютере. Так что если у вас 64-битный процессор, вполне вероятно, что наименьшим значением типа Int будет –263, а наибольшим 263–1.
• Тип Integer
обозначает… э-э-э… тоже целое число. Основная разница в том, что он не имеет ограничения, поэтому может представлять большие числа. Я имею в виду – Int
более эффективен. В качестве примера сохраните следующую функцию в файл:
factorial :: Integer –> Integer
factorial n = product [1..n]
Затем загрузите этот файл в GHCi с помощью команды :l
и проверьте её:
ghci> factorial 50
30414093201713378043612608166064768844377641568960512000000000000
• Тип Float
– это действительное число с плавающей точкой одинарной точности. Добавьте в файл ещё одну функцию:
circumference :: Float –> Float
circumference r = 2 * pi * r
Загрузите дополненный файл и запустите новую функцию:
ghci> circumference 4.0
25.132742
• Тип Double
– это действительное число с плавающей точкой двойной точности. Двойная точность означает, что для представления чисел используется вдвое больше битов, поэтому дополнительная точность требует большего расхода памяти. Добавим в файл ещё одну функцию:
circumference' :: Double –> Double
circumference' r = 2 * pi * r
Загрузите дополненный файл и запустите новую функцию
ghci> circumference' 4.0
25.132741228718345
• Тип Bool
– булевский. Он может принимать только два значения: True
и False
.
• Тип Char
представляет символ Unicode. Его значения записываются в одинарных кавычках. Список символов является строкой.
• Кортежи – это типы, но тип кортежа зависит от его длины и от типа его компонентов. Так что теоретически количество типов кортежей бесконечно – а стало быть, перечислить их все в этой книге нет возможности. Заметьте, что пустой кортеж ()
– это тоже тип, который может содержать единственное значение: ()
.
Типовые переменные
Некоторые функции могут работать с данными разных типов. Например, функция head
принимает список и возвращает его первый элемент. При этом неважно, что именно этот список содержит – числа, символы или вообще другие списки. Функция должна работать со списками, что бы они ни содержали.
Как вы думаете, каков тип функции head
? Проверим, воспользовавшись командой :t
.
ghci> :t head
head :: [a] –> a
Гм-м! Что такое a
? Тип ли это? Мы уже отмечали, что все типы пишутся с большой буквы, так что это точно не может быть типом. В действительности это типовая переменная. Иначе говоря, a
может быть любым типом.
Подобные элементы напоминают «дженерики» в других языках – но только в Haskell они гораздо более мощные, так как позволяют нам легко писать самые общие функции (конечно, если эти функции не используют какие-нибудь специальные свойства конкретных типов).
Функции, в объявлении которых встречаются переменные типа, называются head
выше означает, что она принимает список любого типа и возвращает один элемент того же типа.