Bất cứ ai cũng có thể giải thích sự khác biệt giữa:
- Các kiểu dữ liệu đại số (mà tôi khá quen thuộc)
- Các kiểu dữ liệu đại số tổng quát (điều gì làm cho chúng tổng quát?)
- Các loại quy nạp (ví dụ Coq)
(Đặc biệt là các loại quy nạp.) Cảm ơn bạn.
Bất cứ ai cũng có thể giải thích sự khác biệt giữa:
(Đặc biệt là các loại quy nạp.) Cảm ơn bạn.
Câu trả lời:
Các kiểu dữ liệu đại số cho phép bạn xác định các kiểu đệ quy. Cụ thể, giả sử chúng ta có kiểu dữ liệu
Điều này có nghĩa là là tập nhỏ nhất được tạo bởi các toán tử N i l và C o n s . Chúng ta có thể chính thức hóa điều này bằng cách định nghĩa toán tử F ( X )
và sau đó xác định là
Một ADT tổng quát là những gì chúng ta nhận được khi định nghĩa một toán tử kiểu đệ quy. Ví dụ: chúng ta có thể định nghĩa hàm tạo kiểu sau:
Loại này có nghĩa là một yếu tố của là một tuple có độ dài 2 n đối với một số n , vì mỗi lần chúng ta đi vào N e s t , đối số kiểu được ghép với chính nó. Vì vậy, chúng ta có thể định nghĩa toán tử mà chúng ta muốn lấy một điểm cố định là:
Một loại quy nạp trong Coq thực chất là một GADT, trong đó các chỉ mục của toán tử loại không bị hạn chế đối với các loại khác (ví dụ như trong Haskell), nhưng cũng có thể được lập chỉ mục bởi các giá trị của lý thuyết loại. Điều này cho phép bạn đưa ra các loại cho danh sách được lập chỉ mục độ dài, v.v.
bush
được gọi là GADT. Tôi đã thấy chúng được gọi là loại lồng nhau hoặc không thường xuyên.
bush a
không? Trong ví dụ này, nó là Nest Leaf(a) Leaf(a) Leaf(a) Leaf(a)
, hay Nest ((Nest Leaf(a) Leaf(a)) (Nest Leaf(a) Leaf(a)))
là một ví dụ của tập hợp?
Xem xét các kiểu dữ liệu đại số như:
data List a = Nil | Cons a (List a)
Các kiểu trả về của mỗi hàm tạo trong một kiểu dữ liệu đều giống nhau: Nil
và Cons
cả hai trả về List a
. Nếu chúng tôi cho phép các nhà xây dựng trả về các loại khác nhau, chúng tôi có 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
có loại a -> NullableList a b -> NullableList a NonEmpty
, trong khi Cons
có loại a -> List a -> List a
. Điều quan trọng cần lưu ý NonEmpty
là một loại, không phải là một thuật ngữ. Một vi dụ khac:
data Zero
data Succ n
data SizedList a t where
Alone :: SizedList a Zero
WithFriends :: a -> SizedList a n -> SizedList a (Succ n)
Các kiểu quy nạp trong các ngôn ngữ lập trình có các kiểu phụ thuộc cho phép các kiểu trả về của các hàm tạo phụ thuộc vào các giá trị (không chỉ các kiểu) của các đối số.
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).
Lưu ý bên lề: GHC có một cơ chế xử lý các hàm tạo giá trị như các hàm tạo kiểu . Điều này không giống với các loại quy nạp phụ thuộc mà Coq có, nhưng nó giảm bớt gánh nặng cú pháp của GADT phần nào và nó có thể dẫn đến các thông báo lỗi tốt hơn.