Что такое [] (конструктор списка) в Haskell? - PullRequest
21 голосов
/ 16 февраля 2010

У меня проблемы с пониманием функторов, в частности, что такое конкретный тип в LYAH. Я полагаю, что это потому, что я не понимаю, что такое [].

fmap :: (a -> b) -> f a -> f b  
  1. Является ли [] конструктором типов? Или это конструктор значений?
  2. Что значит иметь тип: [] :: [a]?
  3. Это как Maybe конструктор типа или Just конструктор значения?
    1. Если это похоже на Just, то почему Just имеет подпись вроде Just :: a -> Maybe a вместо Just :: Maybe a, другими словами, почему [] не напечатано [] :: a -> [a]
  4. LYAH говорит это применительно к функторам: Обратите внимание, что мы не написали экземпляр Functor [a] где, потому что из fmap :: (a -> b) -> fa - > fb, мы видим, что f должен быть конструктором типа, который принимает один тип. [a] уже является конкретным типом (списка с любым типом внутри него), в то время как [] является конструктором типов, который принимает один тип и может создавать такие типы, как [Int], [String] или даже [[String] ]. Я в замешательстве, хотя тип [] подразумевает, что это похоже на литерал для [a], к чему стремится ЛЯХ?

Ответы [ 4 ]

20 голосов
/ 16 февраля 2010

Тип описывается (в сеансе 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] появляется в значении .

15 голосов
/ 16 февраля 2010
  1. Синтаксически перегружен (как ни странно, я вам), чтобы быть и конструктором типа, и конструктором значения.

  2. Это означает, что (конструктор значений) [] имеет тип, который для всех типов a представляет собой список a (который записан [a]). Это потому, что в каждом типе есть пустой список.

  3. Конструктор значений [] не набирается a -> [a], поскольку в пустом списке нет элементов, и поэтому для создания пустого списка a не требуется a. Сравните с Nothing :: Maybe a вместо.

  4. LYAH говорит о конструкторе типов [] с типом * -> *, в отличие от конструктора значений [] с типом [a].

9 голосов
/ 16 февраля 2010
  1. это конструктор типа (например, [Int] является типом) и конструктор данных ([2] является структурой списка).
  2. Пустой список - это список, содержащий любой тип
  3. [a] похоже на Maybe a, [2] похоже на Just 2.
  4. [] - нулевая функция (константа), поэтому у нее нет типа функции.
5 голосов
/ 16 февраля 2010

Просто, чтобы сделать вещи более явными, этот тип данных:

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) = ..., сопоставление с шаблоном непустых списков

На самом деле, если вы спросите ghci о [], он скажет вам почти то же определение:

> :i []
data [] a = [] | a : [a]           -- Defined in GHC.Types

Но вы не можете сами написать такое определение, потому что синтаксис списка и его конструктор типа «outfix» - это особый случай, определенный в спецификации языка.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...