У меня Есть проблемы при понимании функторов, конкретно что конкретный тип находится в LYAH. Я полагаю, что это вызвано тем, что я не понимаю что []
действительно.
fmap :: (a -> b) -> f a -> f b
[]
, конструктор типа? Или, действительно ли это - конструктор значения?[] :: [a]
?Maybe
конструктор типа, или Just
конструктор значения? Just
затем, каким образом Just
имеет подпись как Just :: a -> Maybe a
вместо Just :: Maybe a
, другими словами, почему не []
введенный [] :: a -> [a]
[]
конструктор типа, который берет один тип и может произвести типы, такие как [Интервал], [Строка] или даже [[Строка]]. Я смущен хотя тип []
подразумевает, что это похоже на литерал для [a]
что LYAH пытается достигнуть?Это (я допускаю, что это сбивает с толку) синтаксически перегружено, чтобы быть как конструктором типа, так и конструктором значения.
Это означает, что (конструктор значения) []
имеет тип, который для всех типов a
представляет собой список a
(который записывается как [ а]
). Это потому, что у каждого типа есть пустой список.
Конструктор значения []
не типизирован a -> [a]
, потому что пустой список не имеет элементов, и поэтому ему не требуется a
для создания пустой список из
. Сравните с Ничего :: Может быть, вместо
.
LYAH говорит о конструкторе типа []
с видом * -> *
, в отличие от конструктора значения []
с типом [a]
.
Тип описывается (в сеансе GHCI) как:
$ ghci
Prelude> :info []
data [] a = [] | a : [a] -- Defined
Мы также можем думать об этом так, как если бы он был определен как:
data List a = Nil
| Cons a (List a)
или
data List a = EmptyList
| ListElement a (List a)
Конструктор типов
[a]
- это полиморфный тип данных, который также может быть записан [] a
как указано выше. Это можно представить так, как будто это List a
В этом случае []
является конструктором типа , принимающим один аргумент типа a
и возвращающим тип [] a
, который также можно записать как [a]
.
Можно написать такой тип функции:
sum :: (Num a) => [a] -> a
Конструктор данных
[]
- это конструктор данных , что по сути означает «пустой список». Этот конструктор данных не принимает аргументов-значений.
Существует еще один конструктор данных, :
, который добавляет элемент в начало другого списка. Подпись для этого конструктора данных a: [a]
- он принимает элемент и другой список элементов и возвращает результирующий список элементов.
Обозначение []
также может использоваться как сокращение для построения списка.Обычно мы строим список как:
myNums = 3 : 2 : 4 : 7 : 12 : 8 : []
, который интерпретируется как
myNums = 3 : (2 : (4 : (7 : (12 : (8 : [])))))
, но Haskell позволяет нам также использовать сокращение
myNums = [ 3, 2, 4, 7, 12, 8 ]
как эквивалентное по значению, но немного более красивое по виду обозначение.
Неоднозначный случай
Часто встречается неоднозначный случай: [a]
. В зависимости от контекста это обозначение может означать либо «список из a
», либо «список с ровно одним элементом, а именно a
». Первое значение - это предполагаемое значение, когда [a]
появляется внутри типа , тогда как второе значение является предполагаемым значением, когда [a]
появляется внутри значение .
Просто чтобы сделать вещи более явными, этот тип данных:
data List a = Cons a (List a)
| Nil
... имеет ту же структуру, что и встроенный тип списка, но без (более приятного, но потенциально запутанного) специального синтаксиса. Вот как выглядят некоторые соответствия:
List
= []
, конструкторы типов с видом * -> *
List a
= [a]
, типы с видом *
Nil
= []
, значения с полиморфными типами List a
и [a]
соответственноCons
=
, конструкторы данных с типами a -> List a -> List a
и a -> [a] -> [a]
соответственноCons 5 Nil
= [5]
или 5:[]
, одноэлементные спискиf Nil = . ..
= f [] = ...
, сопоставление с образцом пустых списковf (Cons x Nil) = ...
= f [x] = ...`, шаблонное соответствие одноэлементных списковf (Cons x xs) = ...
= f (x:xs) = ...
, pattern matching non-empty listsНа самом деле, если вы спросите ghci о []
, он скажет вам практически такое же определение:
> :i []
data [] a = [] | a : [a] -- Defined in GHC.Types
Но вы не можете написать такое определение сами, потому что синтаксис списка и его конструктор типа "outfix" - это особый случай, определенный в спецификации языка.