2011-07-19 28 views
9

Hãy xem xét các kiểu lớp sau đây:trường Type-class với nhiều loại với 2 thông số khi loại lớp chỉ có một

class Listable a where 
    asList :: a t -> [t] 

Thật dễ dàng đủ để tạo ra trường hợp với nhiều loại với một tham số:

instance Listable [] where 
    asList = id 

instance Listable Maybe where 
    asList (Just x) = [x] 
    asList Nothing = [] 

Bây giờ, làm cách nào để tạo một cá thể cho một cặp có hai tham số kiểu giống nhau? Dĩ nhiên tôi có thể làm một số gói:

data V2 a = V2 a a 

v2 (p,q) = V2 p q 

instance Listable V2 where 
    asList (V2 p q) = [p,q] 

Bây giờ tôi có thể viết những thứ như asList $ v2 (47, 11), nhưng loại đánh bại mục đích.

Có cách nào để giới hạn loại cặp đối với các trường hợp cả hai tham số loại đều bằng nhau và để viết một ví dụ Listable cho điều đó? Nếu không, cách giải quyết thông thường là gì?

Trả lời

13

Có rất nhiều cách để làm điều này, theo khái niệm. Thật không may, hầu hết trong số họ không thực sự làm việc. Than ôi!

Thứ nhất, như một lập trình chức năng, tôi muốn cược rằng đây là những gì bạn thực sự muốn viết:

instance Listable (\a -> (a, a)) where 
    asList (p, q) = [p,q] 

Thật không may gõ cấp lambdas không tồn tại. Chúng tôi có thể viết phiên bản có tên của lambda ở trên bằng cách sử dụng loại đồng nghĩa:

type Same2 f a = f a a 

instance Listable (Same2 (,)) where { ... } 

Không được phép vì loại đồng nghĩa không được áp dụng đầy đủ. Chúng tôi có thể tưởng tượng thay vì lớp loại dùng một tham số bổ sung mà sẽ mô tả làm thế nào để áp dụng các biến loại:

class Listable app f where 
    asList :: app f a -> [a] 

instance Listable __ Maybe where { ... } 

instance Listable __ (,) where { ... } 

Thậm chí không cần suy nghĩ về những gì app có thể, điều này cũng không thành công vì chúng ta không có một loại phù hợp cho tham số f.

Chuyển sang những thứ thực sự hoạt động, tôi nghĩ cách phổ biến nhất là quấn cách tiếp cận đồng nghĩa loại bên trong một newtype, sau đó chỉ xử lý gói và mở bao gồm.

newtype Same2 f a = Same2 (f a a) 

instance Listable (Same2 (,)) where { ... } 

Có thể thực hiện được, nếu có chút xấu xí. Bạn cũng có thể xác định thành phần constructor kiểu và các đồ chơi khác theo cách này, sau đó đi các loại hạt với các biểu thức không có điểm loại không bị chôn vùi dưới một đống bản lồng tiếng hoop-nhảy.

Là một phương pháp cuối cùng, bạn cũng có thể mã hóa các phương pháp lambda-style trên "ngược lại", đi từ phiên bản đầy đủ ứng dụng, - tham số kiểu duy nhất:

class Listable t where 
    type ListableElem t :: * 
    asList :: t -> [ListableElem t] 

Being có thể làm điều này là một trong những động lực chính cho các gia đình kiểu. Điều tương tự có thể được thể hiện bằng MPTC và fundeps, nhưng nó là 1) tương đương và 2) xấu hơn nhiều, vì vậy tôi sẽ không bận tâm viết nó ra.

+0

Xin lỗi vì đã lười biếng để thử nó, nhưng cách tiếp cận cuối cùng sẽ cho phép 'instance Listable (a, a)' - phải không? – yatima2975

+0

@ yatima2975: Với chi phí có các trường hợp khác nhau với '(,)' là hàm tạo ngoài cùng, có. Có lẽ nên đặt nó như một ví dụ trong câu trả lời của tôi, bây giờ bạn nhắc đến nó ... –

2

Bạn phải xác định một số loại trình bao bọc để thực hiện việc này. (Tuy nhiên, bạn nên sử dụng newtype.) Bạn thậm chí có thể xác định:

newtype Foo t a = Foo(t a a) 

instance Listable (Foo (,)) where 
    asList (Foo (a,b)) = [a,b] 
Các vấn đề liên quan