2016-04-13 35 views
6

Tôi vừa bắt đầu học Haskell. Vì Haskell được nhập tĩnh và có suy luận kiểu đa hình, loại chức năng nhận dạng làKhó hiểu về suy luận kiểu Haskell

id :: a -> a 

id đề xuất có thể lấy bất kỳ loại nào làm tham số và tự trả về. Nó hoạt động tốt khi tôi thử:

a = (id 1, id True) 

Tôi giả sử rằng lúc biên dịch, id đầu tiên là Num a :: a -> a và id thứ hai là Bool -> Bool. Khi tôi cố gắng đoạn mã sau, nó mang lại một lỗi:

foo f a b = (f a, f b) 
result = foo id 1 True 

Nó cho thấy loại một phải cùng một loại b, vì nó hoạt động tốt với

result = foo id 1 2 

Nhưng là đúng là loại tham số của id có thể được đa hình, sao cho a và b có thể là loại khác nhau?

+0

là http://stackoverflow.com/questions/32496864/what-is-the-monomorphism-restriction những gì bạn muốn? – hao

+5

@haoformayor Không, đây là về 'forall', không phải là hạn chế đơn hình, tôi nghĩ vậy. Kiểu suy ra cho 'foo' sẽ phải là' (forall a. A -> a) -> a -> b -> (a, b) ', nhưng AFAIK haskell không bao giờ thâm nhập các kiểu với' forall' (được gọi là rank -2 loại, tôi nghĩ vậy?), ngay cả khi hạn chế monomorphism bị vô hiệu hóa. – amalloy

+1

ah, đó là câu trả lời. ghc đưa vào loại rank-1 'forall a b. (a -> b) -> a -> a -> (b, b) ', nhưng bạn thực sự muốn' (forall a. a -> a) -> a -> b -> (a, b) '. – hao

Trả lời

8

Được rồi, đây là một góc ma quái kỳ lạ của hệ thống kiểu Haskell. Vấn đề ở đây là có hai cách để suy luận chức năng của bạn foo.

-- rank 1 
foo :: forall a b. (a -> b) -> a -> a -> (b, b) 
foo f a b = (f a, f b) 

-- rank 2 
foo' :: (forall a. a -> a) -> a -> b -> (a, b) 
foo' f a b = (f a, f b) 

Loại thứ hai là loại bạn muốn, nhưng loại thứ nhất là loại bạn muốn. Loại thứ hai, như amalloy đã chỉ ra, là một loại hạng 2 (chúng ta sẽ bỏ qua ý nghĩa của hai phương pháp này nhưng đọc phần giới thiệu trong "Practical type inference for arbitrary-rank types" nếu bạn muốn giải thích tốt về các cấp bậc - không được đưa ra bởi bản chất của tập tin PDF khi bắt đầu được viết rõ ràng và rõ ràng).

Chúng tôi sẽ hoãn định nghĩa các loại xếp hạng cao hơn hiện tại và chỉ nói rằng vấn đề là GHC không thể suy ra loại xếp hạng 2. Trích dẫn bài báo:

Complete type inference is known to be undecidable for higher-rank (impredicative) type systems, but in practice programmers are more than willing to add type annotations to guide the type inference engine, and to document their code....

Kfoury and Wells show that typeability is decidable for rank ≤ 2, and undecidable for all ranks ≥ 3 (Kfoury & Wells, 1994). For the rank-2 fragment, the same paper gives a type inference algorithm. This inference algorithm is somewhat subtle, does not interact well with user-supplied type annotations, and has not, to our knowledge, been implemented in a production compiler.

Có nghĩa là không thể có thuật toán luôn dẫn đến quyết định có hoặc không chính xác. Vì vậy, có bạn có nó: không thể suy ra một loại cấp bậc 3 hoặc cao hơn, và nó quá gosh-darn-khó để suy ra loại hạng 2.

Bây giờ, quay lại xếp hạng 2. (forall a. a -> a) là thứ giúp xếp hạng 2. There's already an excellent Stack Overflow question about what the forall keyword means vì vậy tôi sẽ giới thiệu bạn đến đó, nhưng về cơ bản nó có nghĩa là bạn có thể gọi f af b trong biểu thức (f a, f b) khi ab thể loại khác nhau, đó là những gì bạn muốn ở nơi đầu tiên, trước khi tất cả mớ hỗn độn nóng bỏng này.

Điều cuối cùng: Lý do bạn thường không thấy forall s trong GHCi là bất kỳ forall giây nào trên phạm vi ngoài cùng đều bị tắt. Vì vậy, forall a b. (a -> b) -> a -> a -> (b, b) tương đương với (a -> b) -> a -> a -> (b, b).

Nhìn chung đây là điểm đau của ngôn ngữ được giải thích kém.

(Hat tip để @amalloy trong các ý kiến.)

+3

Cần lưu ý rằng cả hai loại này đều không chung chung hơn loại kia. Mỗi cái có thể được sử dụng theo cách mà người kia không thể. Vì vậy, 'foo f a b = (f a, f b)' được lấy trong sự cô lập là mơ hồ về hàm nào thực sự được định nghĩa; tại thời điểm đó sự mơ hồ được giải quyết bằng cách diễn giải với một loại bậc 1. Trong một thế giới giả định, nơi GHC có suy luận xếp hạng 2 hoàn hảo và không có hành lý lịch sử nào thích giải thích xếp hạng 1, bạn có thể phải thêm thứ gì đó làm giảm lựa chọn, vì đó không phải là thứ chúng tôi muốn trình biên dịch để chọn cho bạn. – Ben

+1

Là một sang một bên, loại 'forall a. a -> a' là nơi sinh sống chính xác của một giá trị không phải dưới cùng ('id') nên' foo'' về cơ bản là đẳng cấu đối với '(,)'. – user2407038

Các vấn đề liên quan