. Явное указание типа может понадобиться, если мы, к примеру, хотим, чтобы значение
>Just 3
имело тип
>Maybe Int
. По умолчанию Haskell выведет тип
>(Num a) => Maybe a
. Воспользуемся явным аннотированием типа:
>ghci> Just 3 :: Maybe Int
>Just 3
Может, вы и не знали, но мы использовали тип, у которого были типы-параметры ещё до типа >Maybe
. Этот тип – список. Несмотря на то что дело несколько скрывается синтаксическим сахаром, конструктор списка принимает параметр для того, чтобы создать конкретный тип. Значения могут иметь тип >[Int]
, >[Char]
, >[[String]]
, но вы не можете создать значение с типом >[]
.
ПРИМЕЧАНИЕ. Мы называем тип конкретным, если он вообще не принимает никаких параметров (например, >Int
или >Bool
) либо если параметры в типе заполнены (например, >Maybe Char
). Если у вас есть какое-то значение, у него всегда конкретный тип.
Давайте поиграем с типом >Maybe
:
>ghci> Just "Ха-ха"
>Just "Ха-ха"
>ghci> Just 84
>Just 84
>ghci> :t Just "Ха-ха"
>Just "Ха-ха" :: Maybe [Char]
>ghci> :t Just 84
>Just 84 :: (Num t) => Maybe t
>ghci> :t Nothing
>Nothing :: Maybe a
>ghci> Just 10 :: Maybe Double
>Just 10.0
Типы-параметры полезны потому, что мы можем с их помощью создавать различные типы, в зависимости от того, какой тип нам надо хранить в нашем типе данных. К примеру, можно объявить отдельные Maybe-подобные типы данных для любых типов:
>data IntMaybe = INothing | IJust Int
>data StringMaybe = SNothing | SJust String
>data ShapeMaybe = ShNothing | ShJust Shape
Более того, мы можем использовать типы-параметры для определения самого обобщённого >Maybe
, который может содержать данные вообще любых типов!
Обратите внимание: тип значения >Nothing
– >Maybe a
. Это полиморфный тип: в его имени присутствует типовая переменная – конкретнее, переменная >a
в типе >Maybe a
. Если некоторая функция принимает параметр типа >Maybe Int
, мы можем передать ей значение >Nothing
, так как оно не содержит значения, которое могло бы этому препятствовать. Тип >Maybe a
может вести себя как >Maybe Int
, точно так же как значение >5
может рассматриваться как значение типа >Int
или >Double
. Аналогичным образом тип пустого списка – это >[a]
. Пустой список может вести себя как список чего угодно. Вот почему можно производить такие операции, как >[1,2,3] ++ []
и >["ха","ха","ха"] ++ []
.