Может ли кто-нибудь объяснить разницу между:
- Алгебраические типы данных (с которыми я довольно хорошо знаком)
- Обобщенные алгебраические типы данных (что делает их обобщенными?)
- Индуктивные типы (например, Coq)
(Особенно индуктивные типы.) Спасибо.
Может ли кто-нибудь объяснить разницу между:
(Особенно индуктивные типы.) Спасибо.
Ответы:
Алгебраические типы данных позволяют определять типы рекурсивно. Конкретно, предположим, у нас есть тип данных
Это означает, что - это наименьшее множество, генерируемое операторами N i l и C o n s . Мы можем формализовать это, определив оператор F ( X )
и затем определение в
Обобщен ADT является то , что мы получаем , когда определить тип оператора рекурсивно. Например, мы могли бы определить следующий конструктор типа:
Этот тип означает, что элемент является кортежем через с длиной 2 п для некоторого п , таккаждый размы в N е с т конструктора типа аргументпаре с самим собой. Таким образом, мы можем определить оператор, для которого мы хотим взять фиксированную точку:
Индуктивный тип в Coq - это, по сути, GADT, где индексы оператора типа не ограничены другими типами (как, например, в Haskell), но могут также индексироваться значениями теории типов. Это позволяет вам задавать типы для списков с индексацией длины и так далее.
bush
GADT. Я видел их, называемые вложенными или нерегулярными типами.
bush a
? В этом примере это Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a)
или Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))
как один из примеров набора?
Рассмотрим алгебраические типы данных, такие как:
data List a = Nil | Cons a (List a)
Типы возврата каждого конструктора в типе данных все равно: Nil
и Cons
как возвращение List a
. Если мы позволим конструкторам возвращать разные типы, у нас есть GADT :
data Empty -- this is an empty data declaration; Empty has no constructors
data NonEmpty
data NullableList a t where
Vacant :: NullableList a Empty
Occupied :: a -> NullableList a b -> NullableList a NonEmpty
Occupied
имеет тип a -> NullableList a b -> NullableList a NonEmpty
, а Cons
имеет тип a -> List a -> List a
. Важно отметить, что NonEmpty
это тип, а не термин. Другой пример:
data Zero
data Succ n
data SizedList a t where
Alone :: SizedList a Zero
WithFriends :: a -> SizedList a n -> SizedList a (Succ n)
Индуктивные типы в языках программирования, которые имеют зависимые типы, позволяют типам возвращаемых конструкторов зависеть от значений (а не только типов) аргументов.
Inductive Parity := Even | Odd.
Definition flipParity (x:Parity) : Parity :=
match x with
| Even => Odd
| Odd => Even
end.
Fixpoint getParity (x:nat) : Parity :=
match x with
| 0 => Even
| S n => flipParity (getParity n)
end.
(*
A ParityNatList (Some P) is a list in which each member
is a natural number with parity P.
*)
Inductive ParityNatList : option Parity -> Type :=
Nil : forall P, ParityNatList P
| Cons : forall (x:nat) (P:option Parity),
ParityNatList P -> ParityNatList
(match P, getParity x with
| Some Even, Even => Some Even
| Some Odd, Odd => Some Odd
| _, _ => None
end).
Примечание: GHC имеет механизм для обработки конструкторов значений как конструкторов типов . Это не то же самое, что зависимые индуктивные типы, которые есть у Coq, но это несколько уменьшает синтаксическую нагрузку GADT и может привести к улучшению сообщений об ошибках.