2012-02-19 27 views
5

Tôi có các lớp loại, cho tất cả những gì tôi muốn có một số hành vi phổ biến. Vấn đề của tôi được giải thích trong đoạn mã sau:Haskell Không thể suy ra ... từ lỗi Ngữ cảnh

 
class A a 
class B b 

class X x where 
    method :: (A a, B b) => x -> a -> b 

data T = L | M | N 
data U = P | Q | R 

instance A T 
instance B U 

data Y = ZZZ 

instance X Y where 
    method _ L = P 
    method _ M = Q 
    method _ N = R 

Khi tôi nạp mô-đun này, tôi nhận được lỗi sau:

 
example.hs:19:14: 
    Could not deduce (a ~ T) 
    from the context (A a, B b) 
     bound by the type signature for method :: (A a, B b) => Y -> a -> b 
     at example.hs:(17,5)-(19,18) 
     `a' is a rigid type variable bound by 
      the type signature for method :: (A a, B b) => Y -> a -> b 
      at example.hs:17:5 
    In the pattern: N 
    In an equation for `method': method _ N = R 
    In the instance declaration for `X Y' 

example.hs:19:18: 
    Could not deduce (b ~ U) 
    from the context (A a, B b) 
     bound by the type signature for method :: (A a, B b) => Y -> a -> b 
     at example.hs:(17,5)-(19,18) 
     `b' is a rigid type variable bound by 
      the type signature for method :: (A a, B b) => Y -> a -> b 
      at example.hs:17:5 
    In the expression: R 
    In an equation for `method': method _ N = R 
    In the instance declaration for `X Y' 
Failed, modules loaded: none. 

tôi đang ở mất phải làm gì trong trường hợp này. Ngay cả khi T và U là trường hợp của A và B, tôi nhận được lỗi này. Nếu tôi không thể trả lại giá trị loại cứng nhắc từ method, làm cách nào để mã hóa phần này?

+0

có thể trùng lặp của [danh sách loại dữ liệu: "không thể suy ra (a ~ SomeType) từ ngữ cảnh (SomeTypeclass a)"] (http://stackoverflow.com/questions/5453514/lists-of-data-types -có-không-deduce-a-sometype-từ-the-context-sometype) – Landei

Trả lời

9

Chữ ký method :: (A a, B b) => x -> a -> b hứa hẹn rằng method công trình cho mỗi cặp loại (a, b) với a một thể hiện của Ab một thể hiện của B, nhưng bạn định nghĩa nó chỉ làm việc với hai loại cụ thể.

Điều này về cơ bản khác với giao diện trong Java hoặc tương tự, trong đó callee chọn loại được sử dụng, điều duy nhất người gọi biết là giao diện X được triển khai. Trong Haskell, với chữ ký như vậy, người gọi quyết định loại nào được sử dụng (ở đây, loại nào được chuyển làm đối số thứ hai và loại nào sẽ được trả về) và callee phải có khả năng cung cấp chức năng được yêu cầu (miễn là yêu cầu) các kiểu là các thể hiện của các lớp được yêu cầu).

Nếu không có bất kỳ phương pháp trong các lớp AB để phân tích lần lượt là xây dựng giá trị của một thể hiện của lớp đó, bạn không thể thực hiện method khác so với undefined (mức độ khác nhau của undefinedness được thể do seq), do đó bạn sẽ phải nói thế giới mà bạn đang thực tế sử dụng TU.

Một cách khác là làm cho X một lớp kiểu nhanh và nhiều,

{-# LANGUAGE MultiParamTypeClasses #-} 

class (A a, B b) => X x a b where 
    method :: x -> a -> b 

Tuy nhiên, đó có thể yêu cầu phụ thuộc chức năng để giải quyết trường hợp này. Một cách khác là sử dụng các loại được liên kết,

{-# LANGUAGE TypeFamilies #-} 

class X x where 
    type AType x 
    type BType x 
    method :: x -> AType x -> BType x 

instance X Y where 
    type AType Y = T 
    type BType Y = U 
    method ... 
+0

Tôi nhận được quan điểm của bạn. Tôi có các lớp Y, T, U làm việc cùng nhau. Tôi có một bộ ba lớp Y1, T1, U1 hoạt động cùng nhau. Trong bài toán của tôi, các lớp kiểu này tạo thành các cá thể của một mô hình. Tôi muốn có một mã phổ biến hoạt động trên các mô hình này mà không cần quan tâm đến cách chúng được triển khai. Cảm ơn mặc dù đã chỉ ra vấn đề. Loại mã này sẽ là một vấn đề trong java giống như ngôn ngữ. – mutelogan

+0

Đã thêm các lựa chọn thay thế có thể –

+0

Cảm ơn bạn đã giải thích. – mutelogan

3

Thật khó để nghĩ về một cách để giải cứu ví dụ của bạn (vì những lý do được Daniel Fischer đề cập). Nếu bạn có hai loại lớp A và B hoàn toàn không liên quan, bạn nên thiết lập một kết nối chung như thế nào? Vì vậy, bạn có thể đặt cả hai cùng nhau, nhưng tôi nghi ngờ rằng đây là những gì bạn muốn:

{-# LANGUAGE MultiParamTypeClasses #-} 

class A2B a b where 
    convert :: a -> b 

data T = L | M | N 
data U = P | Q | R 

instance A2B T U where 
    convert L = P 
    convert M = Q 
    convert N = R 

data Y = ZZZ 

class X x where 
    method :: (A2B a b) => x -> a -> b 

instance X Y where 
    method _ t = convert t 

Và thiết kế này không phải là rất ổn định một trong hai: Bạn sẽ gặp rắc rối khi bạn muốn có trường hợp như A2B T V bên cạnh A2B T U.

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