Các loại hạng nhất cho phép một cái gì đó gọi là gõ phụ thuộc . Điều này cho phép lập trình viên sử dụng các giá trị của các loại ở cấp độ loại. Ví dụ, loại của tất cả các cặp số nguyên là loại thông thường, trong khi cặp của tất cả các số nguyên có số bên trái nhỏ hơn số bên phải là loại phụ thuộc. Ví dụ giới thiệu tiêu chuẩn về điều này là các danh sách được mã hóa theo chiều dài (thường được gọi là Vector
Haskell / Idris). Mã giả sau đây là hỗn hợp của Idris và Haskell.
-- a natural number
data Nat = Zero | Successor Nat
data Vector length typ where
Empty : Vector Zero typ
(::) : typ -> Vector length typ -> Vector (Successor length) typ
Đoạn mã này cho chúng ta hai điều:
- Danh sách trống có độ dài bằng không.
cons
ing một phần tử vào danh sách tạo ra một danh sách độ dài n + 1
Điều này trông rất giống với một khái niệm khác với 0 và n + 1
, phải không? Tôi sẽ trở lại với điều đó.
Chúng ta đạt được gì từ điều này? Bây giờ chúng ta có thể xác định các thuộc tính bổ sung của các chức năng chúng ta sử dụng. Ví dụ: Một thuộc tính quan trọng append
là độ dài của danh sách kết quả là tổng độ dài của hai danh sách đối số:
plus : Nat -> Nat -> Nat
plus Zero n = n
plus (Successor m) n = Successor (plus m n)
append : Vector n a -> Vector m a -> Vector (plus n m) a
append Empty ys = ys
append (x::xs) ys = x :: append xs ys
Nhưng tất cả trong tất cả các kỹ thuật này dường như không hữu ích trong lập trình hàng ngày. Làm thế nào điều này liên quan đến ổ cắm, POST
/ GET
yêu cầu và như vậy?
Vâng, nó không (ít nhất là không phải không có nỗ lực đáng kể). Nhưng nó có thể giúp chúng ta theo những cách khác:
Các kiểu phụ thuộc cho phép chúng ta xây dựng các bất biến trong mã - các quy tắc như cách một hàm phải hành xử. Sử dụng những điều này, chúng tôi nhận được sự an toàn bổ sung về hành vi của mã, tương tự như trước và sau điều kiện của Eiffel. Điều này cực kỳ hữu ích cho việc chứng minh định lý tự động, đây là một trong những cách sử dụng có thể cho Idris.
Quay trở lại ví dụ trên, định nghĩa về danh sách được mã hóa theo chiều dài giống với khái niệm toán học của cảm ứng . Trong Idris, bạn thực sự có thể hình thành khái niệm cảm ứng trong danh sách như sau:
-- If you can supply the following:
list_induction : (Property : Vector len typ -> Type) -> -- a property to show
(Property Empty) -> -- the base case
((w : a) -> (v : Vector n a) ->
Property v -> Property (w :: v)) -> -- the inductive step
(u : Vector m b) -> -- an arbitrary vector
Property u -- the property holds for all vectors
Kỹ thuật này được giới hạn trong các bằng chứng xây dựng, nhưng dù sao cũng rất mạnh mẽ. Bạn có thể cố gắng viết append
theo quy nạp như một bài tập.
Tất nhiên, các loại phụ thuộc chỉ là một cách sử dụng các loại hạng nhất, nhưng nó được cho là một trong những loại phổ biến nhất. Việc sử dụng bổ sung bao gồm, ví dụ, trả về một loại cụ thể từ một hàm dựa trên các đối số của nó.
type_func : Vector n a -> Type
type_func Empty = Nat
type_func v = Vector (Successor Zero) Nat
f : (v : Vector n a) -> type_func v
f Empty = 0
f vs = length vs :: Empty
Đây là một ví dụ vô nghĩa, nhưng nó cho thấy một cái gì đó bạn không thể mô phỏng nếu không có các loại hạng nhất.