Suy nghĩ về suy luận kiểu như giải quyết một hệ phương trình. Hãy xem xét một ví dụ :
f x = (x,2)
Làm sao chúng ta có thể suy ra các loại f
? Chúng tôi thấy rằng nó là một chức năng:
f :: a -> b
Bên cạnh đó, từ cấu trúc của f
chúng ta có thể thấy rằng phương trình sau đây giữ simulatenously:
b = (c,d)
d = Int
c = a
Bằng cách giải quyết hệ thống này của phương trình chúng ta có thể thấy rằng loại f
là a -> (a, Int)
. Bây giờ chúng ta hãy nhìn vào những điều sau đây (sai lầm) chức năng:
f x = x : x
Loại (:)
là a -> [a] -> [a]
, vì vậy đây tạo ra các hệ thống sau phương trình (giản thể):
a = a
a = [a]
Vì vậy, chúng ta có được một phương trình a = [a]
, từ đó chúng tôi có thể kết luận rằng hệ phương trình này không có giải pháp và do đó mã không được đánh máy tốt. Nếu chúng ta không từ chối phương trình a = [a]
, chúng ta thực sự đi vào một vòng lặp vô hạn để thêm các phương trình a = [a]
, a = [[a]]
, a = [[[a]]]
, v.v ... vào hệ thống của chúng ta. nhưng điều đó sẽ tạo ra các chương trình sai lầm như f x = x : x
để đánh máy).
Bạn cũng có thể kiểm tra điều này trong ghci:
> let f x = x : x
<interactive>:2:15:
Occurs check: cannot construct the infinite type: a0 = [a0]
In the second argument of `(:)', namely `x'
In the expression: x : x
In an equation for `f': f x = x : x
Như các câu hỏi khác của bạn: hệ thống kiểu GHC Haskell là không Turing hoàn tất và typechecker được đảm bảo để ngăn chặn - trừ khi bạn kích hoạt UndecidableInstances
, trong trường hợp này về mặt lý thuyết nó có thể đi vào vòng lặp vô hạn. GHC, tuy nhiên, đảm bảo chấm dứt bằng cách có ngăn xếp đệ quy có độ sâu cố định, do đó không thể xây dựng chương trình mà nó không bao giờ dừng lại (chỉnh sửa: theo nhận xét của CAMcCann. của đệ quy đuôi trên mức loại cho phép lặp mà không tăng độ sâu ngăn xếp). Tuy nhiên, nó có thể làm cho quá trình biên dịch mất nhiều thời gian tùy ý, vì sự phức tạp của suy luận kiểu Hindley-Milner là theo cấp số nhân trong điều tồi tệ nhất (nhưng không phải là trung bình!).) Trường hợp:
dup x = (x,x)
bad = dup . dup . dup . dup . dup . dup . dup . dup
. dup . dup . dup . dup . dup . dup . dup . dup
. dup . dup . dup . dup . dup . dup . dup . dup
. dup . dup . dup . dup . dup . dup . dup . dup
Safe Haskell sẽ không bảo vệ bạn khỏi này - hãy nhìn vào mueval nếu bạn muốn cho phép người dùng có khả năng độc hại biên dịch chương trình Haskell trên hệ thống của bạn.
Hoàn toàn có thể treo GHC qua 'UndecidableInstances'. Tôi không nhớ lại các chi tiết chính xác, nhưng bạn có thể lặp lại mà không cần tăng độ sâu ngăn xếp bằng cách sử dụng thứ gì đó để tính toán đệ quy đuôi. –
@ C.A.McCann Sẽ rất thú vị khi xem ví dụ. Tôi chỉ trích dẫn hướng dẫn. –
Không có một ví dụ trên tay ngay bây giờ, nhưng tôi sẽ đào một cho bạn tối nay. Tôi nhớ là rất khó làm * vô ý *. –