Hãy là đẫm máu. Chúng ta phải định lượng mọi thứ và cung cấp cho miền định lượng. Giá trị có các loại; loại cấp có các loại; các loại sống trong BOX
.
f1 :: forall (k :: BOX).
(forall (a :: k) (m :: k -> *). m a -> Int)
-> Int
f2 :: (forall (k :: BOX) (a :: k) (m :: k -> *). m a -> Int)
-> Int
Bây giờ, trong không loại ví dụ là k
định lượng rõ ràng, vì vậy GHC là quyết định nơi để đặt rằng forall (k :: BOX)
, dựa trên việc và nơi k
được đề cập. Tôi không hoàn toàn chắc chắn rằng tôi hiểu hoặc sẵn sàng bảo vệ chính sách như đã nêu.
Ørjan đưa ra ví dụ tốt về sự khác biệt trong thực tế. Hãy cũng đẫm máu về điều đó. Tôi sẽ viết /\ (a :: k). t
để làm rõ ràng sự trừu tượng tương ứng với forall
và f @ type
cho ứng dụng tương ứng. Trò chơi là chúng ta có thể chọn các đối số @
-ed, nhưng chúng ta phải sẵn sàng để đưa ra bất kỳ đối số /\
nào mà ma quỷ có thể chọn.
Chúng tôi có
x :: forall (a :: *) (m :: * -> *). m a -> Int
và theo đó có thể phát hiện ra rằng f1 x
thực sự là
f1 @ * (/\ (a :: *) (m :: * -> *). x @ a @ m)
Tuy nhiên, nếu chúng tôi cố gắng cung cấp cho f2 x
điều trị tương tự, chúng ta thấy
f2 (/\ (k :: BOX) (a :: k) (m :: k -> *). x @ ?m0 @ ?a0)
?m0 :: *
?a0 :: * -> *
where m a = m0 a0
Các Hệ thống kiểu Haskell xử lý ứng dụng kiểu như hoàn toàn cú pháp, vì vậy cách duy phương trình có thể được giải quyết là bằng cách xác định các chức năng và xác định các đối số
(?m0 :: * -> *) = (m :: k -> *)
(?a0 :: *) = (a :: k)
nhưng những phương trình không được thậm chí cũng kinded, vì k
là không được tự do được chọn: nó là /\
-ed không @
-ed.
Nói chung, để hiểu thấu các loại đa hình này, bạn nên viết ra tất cả các định lượng và sau đó tìm ra cách biến thành trò chơi của bạn chống lại ma quỷ. Ai chọn cái gì, và theo thứ tự nào. Di chuyển forall
bên trong một loại đối số thay đổi lựa chọn của nó, và thường có thể tạo sự khác biệt giữa chiến thắng và thất bại.
Chính xác thì 'k' ở đó là gì? là 'k' biến bất kỳ điều đặc biệt nào như' * '? – Sibi
@Sibi 'k' là một biến kiểu,' * 'là một trong những giá trị" có thể "của nó. Trong các kiểu Haskell có nhiều kiểu giống như các giá trị có kiểu, mặc dù bạn cần các phần mở rộng để sử dụng nhiều hơn các kiểu cố định dựng sẵn như '*' và '* -> *'. –