Thật khó để thêm bất cứ điều gì vào lời giải thích của Andrej hoặc Neel, nhưng tôi sẽ cho nó một phát súng. Tôi sẽ cố gắng giải quyết quan điểm cú pháp, thay vì cố gắng khám phá ngữ nghĩa cơ bản, bởi vì lời giải thích là cơ bản hơn và tôi đưa ra một câu trả lời thẳng thắn hơn cho câu hỏi của bạn.
λ -calculus chứ không phải là hệ thống phức tạp hơn cơ bản Haskell. Tôi đặc biệt tin rằng sự hiện diện của các biến loại có thể khiến bạn bối rối ở một mức độ nhất định.
Tài liệu tham khảo quan trọng như sau:
Mendler, N. (1991). Các loại quy nạp và các ràng buộc loại trong phép tính lambda bậc hai. Tôi không tìm thấy một tài liệu tham khảo trực tuyến Tôi sợ. Tuy nhiên, các tuyên bố và bằng chứng có thể được tìm thấy trong luận án tiến sĩ của Nax (một bài đọc rất được khuyến khích!).
Bad
Bad=Bad→A
A
λx:Bad.x x:Bad→A
và vì thế
(λx:Bad.x x) (λx:Bad.x x):A
Bad=F(Bad)
F(X)XF(X) (trang 39-40 của luận án).
Tất nhiên bạn đang làm việc không phải với các kiểu được xác định theo phương trình mà với các hàm tạo , tức là bạn có
data Bad = Pack (Bad -> A)
hơn là bình đẳng nghiêm ngặt. Tuy nhiên bạn có thể định nghĩa
unpack :: Bad -> (Bad -> A)
unpack (Pack f) = f
đủ để kết quả này tiếp tục được giữ:
(\x:Bad -> unpack x x) (Pack (\x:Bad -> unpack x x))
A
Trong ví dụ thứ hai của bạn, mọi thứ phức tạp hơn một chút, vì bạn có đôi khi dọc theo dòng
Bad=Bad′→A
Bad′BadBad aBad (Not a)
type Not a = a -> False
với
data Not a = Not a
Sẽ dễ dàng giải quyết nếu Haskell cho phép định nghĩa loại như vậy:
type Acc = Not Acc
Trong trường hợp này, bạn có thể xây dựng một tổ hợp vòng lặp theo cách chính xác như trước đây. Tôi nghi ngờ bạn có thể thực hiện một công trình tương tự (nhưng phức tạp hơn) bằng cách sử dụng
data Acc = D (Not Acc)
Vấn đề ở đây là xây dựng một đẳng cấu
Bad Acc <-> Bad (Not Acc)
bạn phải đối phó với phương sai hỗn hợp.