Последний на самом деле не является GADT - это экзистенциально количественно определенный тип данных, объявленный с синтаксисом GADT. Таким образом, он идентичен предыдущему.
Причина, по которой это не GADT, заключается в том, что нет переменной типа, которая уточняется в зависимости от выбора конструктора. Это ключевая новая функциональность, добавленная GADT. Если у вас такой GADT:
data Foo a where
StringFoo :: String -> Foo String
IntFoo :: Int -> Foo Int
Затем сопоставление с образцом для каждого конструктора открывает дополнительную информацию, которую можно использовать внутри предложения сопоставления. Например:
deconstructFoo :: Foo a -> a
deconstructFoo (StringFoo s) = "Hello! " ++ s ++ " is a String!"
deconstructFoo (IntFoo i) = i * 3 + 1
Обратите внимание, что там происходит что-то очень интересное с точки зрения системы типов. deconstructFoo
обещает, что он будет работать для любого выбора a
, если ему передается значение типа Foo a
. Но тогда первое уравнение возвращает String
, а второе уравнение возвращает Int
.
Это то, что вы не можете сделать с обычным типом данных, и новое, что предоставляют GADT. В первом уравнении сопоставление с образцом добавляет к своему контексту ограничение (a ~ String)
. Во втором уравнении совпадение с образцом добавляет (a ~ Int)
.
Если вы не создали тип, для которого сопоставление с образцом может привести к уточнению типа, у вас нет GADT. У вас просто есть тип, объявленный с синтаксисом GADT. И это нормально - во многих отношениях это лучший синтаксис, чем синтаксис базового типа данных. Это просто более подробный вариант для самых простых случаев.
person
Carl
schedule
05.03.2018