Może ktoś będzie w stanie wyjaśnić różnicę między:
- Algebraiczne typy danych (które dość dobrze znam)
- Uogólnione algebraiczne typy danych (co czyni je uogólnionymi?)
- Rodzaje indukcyjne (np. Coq)
(Szczególnie typy indukcyjne.) Dziękuję.
Może ktoś będzie w stanie wyjaśnić różnicę między:
(Szczególnie typy indukcyjne.) Dziękuję.
Odpowiedzi:
Algebraiczne typy danych umożliwiają rekurencyjne definiowanie typów. Konkretnie, załóżmy, że mamy typ danych
Oznacza to, że jest najmniejszym zestawem generowanym przez operatorów i . Możemy to sformalizować, definiując operatorN i l C o n s F ( X )
a następnie zdefiniowanie jako
Uogólnione ADT jest to, co otrzymujemy, kiedy zdefiniować typ operatora rekurencyjnie. Na przykład możemy zdefiniować następujący konstruktor typu:
Ten typ oznacza, że element jest krotką s o długości jakiegoś , ponieważ za każdym razem gdy w konstruktor typ argumentu jest połączony ze sobą . Możemy więc zdefiniować operatora, który chcemy przyjąć jako punkt stały:a 2 n n N e s t
Typ indukcyjny w Coq jest zasadniczo GADT, gdzie indeksy operatora typu nie są ograniczone do innych typów (jak na przykład Haskell), ale mogą być również indeksowane według wartości teorii typów. Dzięki temu możesz podać typy list indeksowanych według długości i tak dalej.
bush
GADT. Widziałem je nazywane typami zagnieżdżonymi lub nieregularnymi.
bush a
? W tym przykładzie jest to Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a)
, czy Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))
jako jeden z przykładów zestawu?
Rozważ algebraiczne typy danych, takie jak:
data List a = Nil | Cons a (List a)
Rodzaje powrotne każdego konstruktora w typ danych są takie same: Nil
i Cons
obaj powrót List a
. Jeśli pozwolimy konstruktorom zwracać różne typy, mamy 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
ma typ a -> NullableList a b -> NullableList a NonEmpty
, a Cons
ma typ a -> List a -> List a
. Należy zauważyć, że NonEmpty
jest to typ, a nie termin. Inny przykład:
data Zero
data Succ n
data SizedList a t where
Alone :: SizedList a Zero
WithFriends :: a -> SizedList a n -> SizedList a (Succ n)
Typy indukcyjne w językach programowania, które mają typy zależne, pozwalają typom zwracanym przez konstruktory zależeć od wartości (nie tylko typów) argumentów.
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).
Uwaga dodatkowa: GHC ma mechanizm traktowania konstruktorów wartości jako konstruktorów typów . Nie jest to to samo co zależne typy indukcyjne, które posiada Coq, ale nieco zmniejsza obciążenie składniowe GADT i może prowadzić do lepszych komunikatów o błędach.