2012-09-13 12 views
5

Tôi có một cái gì đó như sau:bảo lãnh mà các gia đình loại sẽ lấy được lớp nhất định

{-# LANGUAGE TypeFamilies #-} 

class Configuration c where 
    data Pig c 
    data Cow c 

    parsePig :: GenParser Char st (Pig c) 
    parseCow :: GenParser Char st (Cow c) 

data Farm c = 
    { pigs :: [Pig c] 
    , cows :: [Cow c] 
    } deriving Show 

này không thành công vì dòng deriving Show. Tôi không biết cách ép buộc tất cả các trường hợp Configuration để đảm bảo rằng các triển khai data Pigdata Cow của chúng tôi là tất cả các trường hợp của Show.

Tôi biết tôi có thể làm cho nó có phương pháp showPigshowCow và viết toàn bộ trường hợp phức tạp show, nhưng trong thực tế mọi thứ phức tạp hơn điều này và điều đó sẽ là một nỗi đau.

Có cách nào dễ dàng, thanh lịch để đảm bảo rằng các thể loại gia đình kiểu đó là bản thân các trường hợp của các lớp nhất định không?

+1

Nó không thất bại vì dòng 'LANGAUGE'? –

+1

Đó không phải là toàn bộ tệp; Tôi đã bỏ nó xuống cho các mục đích của câu hỏi này. Rõ ràng là có một khai báo mô-đun, một nhập khẩu ParserCombinators.Parsec, v.v. – So8res

+2

Tôi nghĩ rằng Matt có nghĩa là thực tế là dòng ghi 'LANGAUGE' trong khi nó phải là' LANGUAGE'. –

Trả lời

8

Bạn có thể sử dụng StandaloneDeriving để chỉ định các ràng buộc theo cách thủ công chỉ cho trường hợp Show.

{-# LANGUAGE StandaloneDeriving, FlexibleContexts, UndecidableInstances #-} 
deriving instance (Show (Pig c), Show (Cow c)) => Show (Farm c) 

này vẫn sẽ cho phép bạn có Configuration hợp với CowPig mà không thực hiện Show, tuy nhiên, miễn là bạn không cố gắng show họ.

1

Vì bạn nói rằng bạn muốn lực tất cả các trường của ConfigurationPig cCow c thực hiện Show, một cách đơn giản hơn để làm điều này chỉ đơn giản là hạn chế các gia đình loại trong bối cảnh của lớp học, như vậy:

{-# LANGUAGE TypeFamilies, FlexibleContexts #-} 

class (Show (Pig c), Show (Cow c)) => Configuration c where 
    data Pig c 
    data Cow c 

data Farm c = Farm { pigs :: [Pig c], 
        cows :: [Cow c] } deriving (Show) 

EDIT:

Như @hammar đã chỉ ra trong nhận xét của mình, mã trước đó sẽ không biên dịch. Một cách để khắc phục điều này là sử dụng StandaloneDeriving, như ông đã gợi ý. Một cách khác là thế này:

{-# LANGUAGE TypeFamilies, FlexibleContexts, GADTSyntax #-} 

class (Show (Pig c), Show (Cow c)) => Configuration c where 
    data Pig c 
    data Cow c 

data Farm c where 
    Farm :: Configuration c => { pigs :: [Pig c], 
           cows :: [Cow c] } -> Farm c deriving (Show) 

Hai phương pháp giúp bạn có được kết quả hơi khác nhau, trong cách tiếp cận mà @ Hammar sẽ đòi hỏi một hạn chế Configuration nếu bạn gọi show, trong khi cách tiếp cận của tôi sẽ cung cấp nói hạn chế.

+1

Điều này không biên dịch (sử dụng GHC 7.4.1, ít nhất). Tuy nhiên, kết hợp điều này với phương thức 'StandaloneDeriving' bằng cách sử dụng' deriving instance Configuration c => Show (Farm c) 'tránh sự cần thiết của' UndecidableInstances'. – hammar