Vì vậy, đây thực sự là một tài liệu được tham khảo bởi Meijer và một vài người khác gọi là " Lập trình chức năng với Chuối, Ống kính, Phong bì và Dây thép gai ", ý tưởng cơ bản là chúng ta có thể lấy bất kỳ loại dữ liệu đệ quy nào, như nói
data List = Cons Int List | Nil
và chúng ta có thể tính ra đệ quy thành một biến kiểu
data ListF a = Cons Int a | Nil
lý do tại sao tôi nối thêm đó F
là bởi vì đây là một functor! Nó cũng cho phép chúng ta bắt chước các danh sách, nhưng với một nút thắt: để xây dựng danh sách, chúng ta phải lồng loại danh sách
type ThreeList = ListF (ListF (ListF Void)))
Để khôi phục danh sách ban đầu của chúng tôi, chúng tôi cần phải tiếp tục làm tổ này vô cùng . Điều đó sẽ cho chúng ta một loại ListFF
nơi
ListF ListFF == ListFF
Để làm điều này xác định một "loại điểm cố định"
data Fix f = Fix {unfix :: f (Fix f)}
type ListFF = Fix ListF
Như một bài tập, bạn nên xác minh điều này thỏa mãn phương trình trên của chúng tôi. Bây giờ chúng ta cuối cùng có thể định nghĩa chuối là gì (dị hình)!
type ListAlg a = ListF a -> a
ListAlg
s là loại "danh sách đại số" và chúng ta có thể định nghĩa một hàm cụ thể
cata :: ListAlg a -> ListFF -> a
cata f = f . fmap (cata f) . unfix
Hơn nữa
cata :: ListAlg a -> ListFF -> a
cata :: (Either () (Int, a) -> a) -> ListFF -> a
cata :: (() -> a) -> ((Int, a) -> a) -> ListFF -> a
cata :: a -> (Int -> a -> a) -> ListFF -> a
cata :: (Int -> a -> a) -> a -> [Int] -> a
Nhìn có quen không? cata
chính xác giống như nếp gấp bên phải!
Điều thực sự thú vị là chúng ta có thể làm điều này hơn là chỉ liệt kê, bất kỳ loại nào được xác định bằng "điểm cố định" này đều có cata
và để chứa tất cả chúng ta chỉ cần thư giãn chữ ký loại
cata :: (f a -> a) -> Fix f -> a
Điều này thực sự được lấy cảm hứng từ một phần của lý thuyết thể loại mà tôi đã viết , nhưng đây là phần thịt của phía Haskell.