Lý thuyết loại phụ thuộc và các hàm loại 'tùy ý'
Câu trả lời đầu tiên của tôi cho câu hỏi này là cao về các khái niệm và thấp về chi tiết và được phản ánh về câu hỏi phụ, 'chuyện gì đang xảy ra?'; câu trả lời này sẽ giống nhau nhưng tập trung vào truy vấn con, 'chúng ta có thể có các hàm loại tùy ý không?'.
Một phần mở rộng cho các phép toán đại số của tổng và sản phẩm được gọi là 'toán tử lớn', đại diện cho tổng và tích của một chuỗi (hay nói chung hơn là tổng và tích của hàm trên một miền) thường được viết Σ
và Π
tương ứng. Xem ký hiệu Sigma .
Vậy tổng
a₀ + a₁X + a₂X² + ...
có thể được viết
Σ[i ∈ ℕ]aᵢXⁱ
nơi a
một số chuỗi các số thực, ví dụ. Sản phẩm sẽ được đại diện tương tự với Π
thay vì Σ
.
Khi bạn nhìn từ xa, loại biểu thức này trông rất giống chức năng 'tùy ý' trong X
; tất nhiên chúng tôi giới hạn trong chuỗi có thể biểu thị và các chức năng phân tích liên quan của chúng. Đây có phải là một ứng cử viên cho một đại diện trong một lý thuyết loại? Chắc chắn rồi!
Lớp lý thuyết loại có biểu diễn ngay lập tức của các biểu thức này là lớp lý thuyết loại 'phụ thuộc': lý thuyết với loại phụ thuộc. Đương nhiên, chúng ta có các thuật ngữ phụ thuộc vào các thuật ngữ và trong các ngôn ngữ như Haskell với các hàm loại và định lượng kiểu, thuật ngữ và loại tùy thuộc vào loại. Trong một cài đặt phụ thuộc, chúng tôi cũng có các loại tùy thuộc vào các điều khoản. Haskell không phải là một ngôn ngữ được gõ phụ thuộc, mặc dù nhiều tính năng của các loại phụ thuộc có thể được mô phỏng bằng cách tra tấn ngôn ngữ một chút .
Curry-Howard và các loại phụ thuộc
'Đồng phân Curry-Howard bắt đầu cuộc sống như một quan sát rằng các thuật ngữ và quy tắc đánh giá loại của phép tính lambda được gõ đơn giản tương ứng chính xác với suy luận tự nhiên (theo công thức của Gentzen) áp dụng cho logic mệnh đề trực giác, với các kiểu thay thế cho các mệnh đề và các điều khoản thay thế bằng chứng, mặc dù cả hai được phát minh / phát hiện độc lập. Kể từ đó, nó là một nguồn cảm hứng lớn cho các nhà lý thuyết loại. Một trong những điều rõ ràng nhất để xem xét là liệu, và làm thế nào, sự tương ứng này cho logic mệnh đề có thể được mở rộng để logic vị ngữ hoặc thứ tự cao hơn. Các lý thuyết loại phụ thuộc ban đầu nảy sinh từ con đường thăm dò này.
Để biết giới thiệu về đẳng cấu Curry-Howard cho phép tính lambda được gõ đơn giản, xem tại đây . Ví dụ, nếu chúng ta muốn chứng minh, A ∧ B
chúng ta phải chứng minh A
và chứng minh B
; một bằng chứng kết hợp chỉ đơn giản là một cặp bằng chứng: một cho mỗi kết luận.
Trong khấu trừ tự nhiên:
Γ ⊢ A Γ ⊢ B
Γ ⊢ A ∧ B
và trong phép tính lambda được gõ đơn giản:
Γ ⊢ a : A Γ ⊢ b : B
Γ ⊢ (a, b) : A × B
Tương ứng tương tự tồn tại cho ∨
các loại và tổng, →
và các loại chức năng, và các quy tắc loại bỏ khác nhau.
Một đề xuất không thể chứng minh (sai trực giác) tương ứng với một loại không có người ở.
Với sự tương tự của các loại như các đề xuất logic trong tâm trí, chúng ta có thể bắt đầu xem xét cách mô hình các vị từ trong thế giới loại. Có nhiều cách mà điều này đã được chính thức hóa (xem phần giới thiệu về Lý thuyết loại trực giác của Martin-Löf cho một tiêu chuẩn được sử dụng rộng rãi) nhưng cách tiếp cận trừu tượng thường quan sát rằng một vị ngữ giống như một mệnh đề với các biến thuật ngữ tự do, hoặc, thay vào đó, một hàm lấy các điều khoản cho các mệnh đề. Nếu chúng ta cho phép các biểu thức kiểu chứa các thuật ngữ, thì một cách xử lý theo kiểu tính toán lambda ngay lập tức thể hiện chính nó như một khả năng!
Chỉ xem xét các bằng chứng mang tính xây dựng, những gì tạo thành một bằng chứng về ∀x ∈ X.P(x)
? Chúng ta có thể nghĩ về nó như là một hàm chứng minh, lấy các số hạng ( x
) để chứng minh các mệnh đề tương ứng của chúng ( P(x)
). Vì vậy, các thành viên (bằng chứng) của các loại (đề xuất) ∀x : X.P(x)
là 'chức năng phụ thuộc', mà đối với từng x
ở X
cho một thuật ngữ kiểu P(x)
.
Thế còn ∃x ∈ X.P(x)
? Chúng ta cần bất kỳ thành viên của X
, x
cùng với một bằng chứng P(x)
. Vì vậy, các thành viên (bằng chứng) của loại (mệnh đề) ∃x : X.P(x)
là "cặp phụ thuộc": một thuật ngữ phân biệt x
trong X
, cùng với một thuật ngữ loại P(x)
.
Ký hiệu: Tôi sẽ sử dụng
∀x ∈ X...
cho các tuyên bố thực tế về các thành viên của lớp X
và
∀x : X...
cho các biểu thức loại tương ứng với định lượng phổ quát trên loại X
. Tương tự như vậy cho ∃
.
Kết hợp cân nhắc: sản phẩm và tổng
Cũng như sự tương ứng của các loại Curry-Howard với các mệnh đề, chúng ta có sự tương ứng kết hợp của các loại đại số với các số và hàm, đây là điểm chính của câu hỏi này. Hạnh phúc, điều này có thể được mở rộng cho các loại phụ thuộc được nêu ở trên!
Tôi sẽ sử dụng ký hiệu mô-đun
|A|
để biểu thị 'kích thước' của một loại A
, để làm rõ ràng sự tương ứng được nêu trong câu hỏi, giữa các loại và số. Lưu ý rằng đây là một khái niệm bên ngoài lý thuyết; Tôi không khẳng định rằng cần có bất kỳ nhà khai thác nào như vậy trong ngôn ngữ.
Hãy để chúng tôi đếm các thành viên có thể (giảm hoàn toàn, hợp quy)
∀x : X.P(x)
đó là loại hàm phụ thuộc lấy từ x
loại này X
sang loại khác P(x)
. Mỗi hàm như vậy phải có đầu ra cho mỗi số hạng X
và đầu ra này phải thuộc một loại cụ thể. Đối với mỗi x
trong X
, sau đó, điều này mang lại |P(x)|
'lựa chọn' đầu ra.
Phần cuối là
|∀x : X.P(x)| = Π[x : X]|P(x)|
điều này tất nhiên không có ý nghĩa lớn nếu X
có IO ()
, nhưng có thể áp dụng cho các loại đại số.
Tương tự, một thuật ngữ loại
∃x : X.P(x)
là loại cặp (x, p)
với p : P(x)
, do đó, bất kỳ ai x
trong X
chúng ta cũng có thể xây dựng một cặp thích hợp với bất kỳ thành viên nào P(x)
, đưa ra |P(x)|
'lựa chọn'.
Vì thế,
|∃x : X.P(x)| = Σ[x : X]|P(x)|
với những cảnh báo tương tự
Điều này biện minh cho ký hiệu phổ biến cho các loại phụ thuộc trong các lý thuyết bằng cách sử dụng các ký hiệu Π
và Σ
thực tế, nhiều lý thuyết làm mờ sự khác biệt giữa 'cho tất cả' và 'sản phẩm' và giữa 'có' và 'tổng', do các tương ứng đã đề cập ở trên.
Chúng tôi đang đến gần!
Các vectơ: đại diện cho các bộ dữ liệu phụ thuộc
Bây giờ chúng ta có thể mã hóa các biểu thức số như
Σ[n ∈ ℕ]Xⁿ
như biểu thức kiểu?
Không hẳn. Mặc dù chúng ta có thể xem xét một cách không chính thức ý nghĩa của các biểu thức như Xⁿ
trong Haskell, đâu X
là loại và n
số tự nhiên, đó là sự lạm dụng ký hiệu; đây là biểu thức kiểu chứa một số: rõ ràng không phải là biểu thức hợp lệ.
Mặt khác, với các loại phụ thuộc trong ảnh, các loại chứa số chính xác là điểm; trong thực tế, các bộ dữ liệu phụ thuộc hoặc "vectơ" là một ví dụ rất phổ biến về cách các loại phụ thuộc có thể cung cấp sự an toàn ở mức loại thực dụng cho các hoạt động như truy cập danh sách . Một vectơ chỉ là một danh sách cùng với thông tin cấp độ liên quan đến độ dài của nó: chính xác những gì chúng ta đang theo dõi cho các biểu thức kiểu như thế nào Xⁿ
.
Trong thời gian của câu trả lời này, hãy để
Vec X n
là loại n
vectơ có độ dài của các X
giá trị -type.
Về mặt kỹ thuật n
ở đây, chứ không phải là một số tự nhiên thực tế , một đại diện trong hệ thống của một số tự nhiên. Chúng ta có thể biểu diễn các số tự nhiên ( Nat
) theo kiểu Peano là zero ( 0
) hoặc người kế thừa ( S
) của một số tự nhiên khác và đối với n ∈ ℕ
tôi viết ˻n˼
có nghĩa là thuật ngữ Nat
đại diện n
. Ví dụ, ˻3˼
là S (S (S 0))
.
Sau đó chúng tôi có
|Vec X ˻n˼| = |X|ⁿ
cho bất kỳ n ∈ ℕ
.
Nat loại: quảng bá ℕ điều khoản cho các loại
Bây giờ chúng ta có thể mã hóa các biểu thức như
Σ[n ∈ ℕ]Xⁿ
như các loại. Biểu thức cụ thể này sẽ làm phát sinh một loại tất nhiên là đồng hình với loại danh sách X
, như được xác định trong câu hỏi. (Không chỉ có vậy, nhưng từ một điểm loại lý thuyết của xem, các loại chức năng - đó là một functor - dùng X
để loại trên là một cách tự nhiên đẳng cấu lại danh sách functor.)
Một mảnh cuối cùng của câu đố cho các hàm 'tùy ý' là cách mã hóa, cho
f : ℕ → ℕ
biểu thức như
Σ[n ∈ ℕ]f(n)Xⁿ
để chúng ta có thể áp dụng các hệ số tùy ý cho một chuỗi lũy thừa.
Chúng ta đã hiểu sự tương ứng của các loại đại số với các số, cho phép chúng ta ánh xạ từ loại này sang số và loại hàm đến hàm số. Chúng ta cũng có thể đi một con đường khác! - lấy một số tự nhiên, rõ ràng có một loại đại số có thể xác định với nhiều thành viên hạn, cho dù chúng ta có loại phụ thuộc hay không. Chúng ta có thể dễ dàng chứng minh điều này bên ngoài lý thuyết loại bằng cảm ứng. Những gì chúng ta cần là một cách để ánh xạ từ số tự nhiên đến các loại, bên trong hệ thống.
Một nhận thức thú vị là, một khi chúng ta có các loại phụ thuộc, bằng chứng bằng cảm ứng và xây dựng bằng đệ quy trở nên giống nhau - thực sự chúng là những thứ rất giống nhau trong nhiều lý thuyết. Vì chúng ta có thể chứng minh bằng cách cảm ứng rằng các loại tồn tại đáp ứng nhu cầu của chúng ta, nên chúng ta không thể xây dựng chúng?
Có một số cách để thể hiện các loại ở cấp độ hạn. Tôi sẽ sử dụng ở đây một ký hiệu Haskellish tưởng tượng với *
vũ trụ các loại, bản thân nó thường được coi là một loại trong một thiết lập phụ thuộc. 1
Tương tự như vậy, cũng có ít nhất nhiều cách để ghi chú ' ℕ
tổng hợp' như có các lý thuyết loại phụ thuộc. Tôi sẽ sử dụng ký hiệu khớp mẫu Haskellish.
Chúng ta cần một ánh xạ, α
từ Nat
đến *
, với thuộc tính
∀n ∈ ℕ.|α ˻n˼| = n.
Các giả định sau đủ.
data Zero -- empty type
data Successor a = Z | Suc a -- Successor ≅ Maybe
α : Nat -> *
α 0 = Zero
α (S n) = Successor (α n)
Vì vậy, chúng ta thấy rằng hành động α
phản chiếu hành vi của người kế vị S
, làm cho nó trở thành một loại đồng hình. Successor
là một hàm loại 'thêm một' vào số lượng thành viên của một loại; đó là, |Successor a| = 1 + |a|
cho bất kỳ a
với một kích thước xác định.
Ví dụ α ˻4˼
(đó là α (S (S (S (S 0))))
), là
Successor (Successor (Successor (Successor Zero)))
và các điều khoản của loại này là
Z
Suc Z
Suc (Suc Z)
Suc (Suc (Suc Z))
cho chúng tôi chính xác bốn yếu tố : |α ˻4˼| = 4
.
Tương tự như vậy, đối với bất kỳ n ∈ ℕ
, chúng ta có
|α ˻n˼| = n
theo yêu cầu.
- Nhiều lý thuyết yêu cầu rằng các thành viên
*
chỉ là đại diện của các loại và một hoạt động được cung cấp dưới dạng ánh xạ rõ ràng từ các điều khoản của loại *
đến các loại liên quan của chúng. Các lý thuyết khác cho phép bản thân các loại chữ là các thực thể cấp hạn.
Chức năng 'tùy ý'?
Bây giờ chúng ta có bộ máy để thể hiện một loạt sức mạnh tổng quát như một loại!
Bộ truyện
Σ[n ∈ ℕ]f(n)Xⁿ
trở thành kiểu
∃n : Nat.α (˻f˼ n) × (Vec X n)
trong đó ˻f˼ : Nat → Nat
một số đại diện phù hợp trong ngôn ngữ của chức năng f
. Chúng ta có thể thấy điều này như sau.
|∃n : Nat.α (˻f˼ n) × (Vec X n)|
= Σ[n : Nat]|α (˻f˼ n) × (Vec X n)| (property of ∃ types)
= Σ[n ∈ ℕ]|α (˻f˼ ˻n˼) × (Vec X ˻n˼)| (switching Nat for ℕ)
= Σ[n ∈ ℕ]|α ˻f(n)˼ × (Vec X ˻n˼)| (applying ˻f˼ to ˻n˼)
= Σ[n ∈ ℕ]|α ˻f(n)˼||Vec X ˻n˼| (splitting product)
= Σ[n ∈ ℕ]f(n)|X|ⁿ (properties of α and Vec)
Làm thế nào 'tùy tiện' là thế này? Chúng tôi không chỉ giới hạn ở các hệ số nguyên theo phương pháp này mà còn cả các số tự nhiên. Ngoài ra, f
có thể là bất cứ điều gì, với một ngôn ngữ Turing Complete với các loại phụ thuộc, chúng ta có thể biểu diễn bất kỳ hàm phân tích nào với các hệ số số tự nhiên.
Tôi đã không điều tra sự tương tác của điều này với, ví dụ, trường hợp được cung cấp trong câu hỏi List X ≅ 1/(1 - X)
hoặc điều gì có thể có nghĩa là 'loại' âm và không nguyên có thể có trong bối cảnh này.
Hy vọng rằng câu trả lời này đi một số cách để khám phá chúng ta có thể đi bao xa với các hàm loại tùy ý.