Không có giới hạn nào cả! Khi tôi bắt đầu học cơ sở lý thuyết thể loại cho các nhà xây dựng kiểu, chính điểm này cũng làm tôi bối rối. Chúng ta sẽ đến đó. Nhưng trước tiên, hãy để tôi làm sáng tỏ một số nhầm lẫn. Hai trích dẫn:
một functor như vậy chỉ có thể có một thể loại mục tiêu một thể loại được xây dựng bằng cách sử dụng một hàm tạo
và
người ta có thể nghĩ rằng functor có bất kỳ thể loại nào là mục tiêu của functor, ví dụ như thể loại của tất cả các loại Haskell
cho thấy rằng bạn đang hiểu nhầm một functor là gì (hoặc ít nhất, bạn đang sử dụng thuật ngữ sai).
Functor không xây dựng thể loại. Một functor là một ánh xạ giữa các thể loại. Functor mang các đối tượng và hình thái (loại và chức năng) trong thể loại nguồn cho đối tượng và hình thái trong thể loại mục tiêu.
Lưu ý rằng điều này có nghĩa là một functor thực sự là một cặp ánh xạ: ánh xạ trên các đối tượng F_obj và ánh xạ trên các hình thái F_morph . Trong Haskell, phần đối tượng F_obj của functor là tên của hàm tạo kiểu (ví dụ List
), trong khi phần hình thái là hàm fmap
(tùy thuộc vào trình biên dịch Haskell để sắp xếp mà fmap
chúng ta đang đề cập đến trong bất kỳ biểu thức đã cho nào). Vì vậy, chúng ta không thể nói rằng đó List
là một functor; chỉ có sự kết hợp của List
và fmap
là một functor. Tuy nhiên, mọi người lạm dụng ký hiệu; các lập trình viên gọi List
một functor, trong khi các nhà lý thuyết thể loại sử dụng cùng một biểu tượng để chỉ cả hai phần của functor.
Hơn nữa, trong lập trình, hầu hết tất cả các functor đều là endofunctor , nghĩa là, loại nguồn và mục tiêu là như nhau - loại của tất cả các loại trong ngôn ngữ của chúng tôi. Hãy gọi thể loại này Loại . Một endofunctor F trên Type ánh xạ một loại T sang loại FT khác và một chức năng T -> S sang một chức năng khác FT -> FS . Bản đồ này tất nhiên phải tuân theo luật functor.
Sử dụng List
như một ví dụ: chúng ta có một hàm tạo kiểu List : Type -> Type
và một hàm fmap: (a -> b) -> (List a -> List b)
, cùng nhau tạo thành một functor. T
Có một điểm cuối cùng để làm sáng tỏ. Viết List int
không tạo ra một loại danh sách số nguyên mới. Loại này đã tồn tại . Đó là một đối tượng trong nhóm của chúng tôi Loại . List Int
chỉ đơn giản là một cách để tham khảo nó.
Bây giờ, bạn đang tự hỏi tại sao một functor không thể ánh xạ một loại, nói, Int
hoặc String
. Nhưng nó có thể! Người ta chỉ phải sử dụng functor danh tính. Đối với bất kỳ loại C nào , functor danh tính ánh xạ mọi đối tượng vào chính nó và hình thái cho chính nó. Thật đơn giản để xác minh ánh xạ này thỏa mãn các luật functor. Trong Haskell, đây sẽ là một hàm tạo kiểu id : * -> *
ánh xạ mọi kiểu tới chính nó. Ví dụ, id int
đánh giá để int
.
Hơn nữa, người ta thậm chí có thể tạo functor không đổi , ánh xạ tất cả các loại thành một loại duy nhất. Ví dụ, functor ToInt : * -> *
, nơi ToInt a = int
dành cho tất cả các loại a
và ánh xạ tất cả các hình thái vào hàm nhận dạng số nguyên: fmap f = \x -> x