2016-09-07 17 views
22

Sử dụng gói cassava, sau đây biên dịch:Sự khác biệt giữa `DeriveAnyClass` và một ví dụ trống là gì?

{-# LANGUAGE DeriveGeneriC#-} 

import Data.Csv 
import GHC.Generics 

data Foo = Foo { foo :: Int } deriving (Generic) 
instance ToNamedRecord Foo 

Tuy nhiên, sau đây không:

{-# LANGUAGE DeriveGeneriC#-} 
{-# LANGUAGE DeriveAnyClass #-} 

import Data.Csv 
import GHC.Generics 

data Foo = Foo { foo :: Int } deriving (Generic, ToNamedRecord) 

Các báo cáo trình biên dịch:

test.hs:7:50: 
    No instance for (ToNamedRecord Int) 
     arising from the first field of ‘Foo’ (type ‘Int’) 
    Possible fix: 
     use a standalone 'deriving instance' declaration, 
     so you can specify the instance context yourself 
    When deriving the instance for (ToNamedRecord Foo) 

này khiến tôi với hai câu hỏi: Tại sao phiên bản thứ hai không giống với phiên bản đầu tiên? Và tại sao trình biên dịch lại hy vọng tìm được một thể hiện cho ToNamedRecord Int?

+1

Tôi chưa thấy 'DeriveAnyClass' làm bất kỳ điều gì hữu ích. Tôi đã thấy nó tạo ra tai nạn thời gian biên dịch, tuy nhiên. Methinks 'tis buggy. – dfeuer

Trả lời

15

The GHC docs nói:

Bối cảnh dụ sẽ được tạo theo các quy tắc tương sử dụng khi phát sinh Eq (nếu loại loại là *), hoặc các quy tắc cho functor (nếu loại của loại là (* -> *)). Ví dụ

instance C a => C (a,b) where ... 

data T a b = MkT a (a,b) deriving(C) 

Mệnh deriving sẽ tạo

instance C a => C (T a b) where {} 

Các trở ngại C aC (a,b) được tạo ra từ các đối số nhà xây dựng dữ liệu, nhưng đơn giản hoá sau để C a.

Vì vậy, theo Eq quy tắc, điều khoản deriving của bạn tạo ra ...

instance ToNamedRecord Int => ToNamedRecord Foo where 

... mà không phải là giống như ...

instance ToNamedRecord Foo where 

... trong đó trước đây chỉ hợp lệ nếu có một phạm vi instance ToNamedRecord Int (xuất hiện ở đó không có trong trường hợp của bạn).

Nhưng tôi thấy thông số kỹ thuật hơi mơ hồ. Ví dụ có thực sự tạo ra mã đó hay nó sẽ tạo ra instance (C a, C (a, b)) => instance C (T a b) và để người giải quyết xả ràng buộc thứ hai? Nó xuất hiện, trong ví dụ của bạn, rằng nó tạo ra các ràng buộc như vậy ngay cả đối với các trường có các kiểu hoàn toàn cụ thể.

Tôi ngần ngại gọi đây là một lỗi, bởi vì nó là cách Eq tác phẩm, nhưng cho rằng DeriveAnyClass được thiết kế để làm cho nó nhanh hơn để viết trống trường hợp nó dường như unintuitive.

+4

Cảm ơn, điều này giải thích mọi thứ hoàn toàn! Bây giờ bạn đã nhấn mạnh vấn đề đang được giải quyết ("Ngữ cảnh nào nên được đưa ra cho cá thể?"), Tôi có thể thấy lý do tại sao các nhân viên GHC đưa ra quyết định họ đã làm - và tôi vẫn bắt đầu xem xét việc này . Các điều kiện mà theo đó nó sẽ "Chỉ làm việc" có vẻ cực kỳ cụ thể, và công việc nó tiết kiệm trong những điều kiện có vẻ khá nhỏ thực sự. –

+3

Tôi đồng ý. Hầu hết (tất cả?) của các lớp mà 'DeriveAnyClass' hữu ích sẽ dựa vào một siêu lớp cấp cao nhất như' Generic' hoặc 'Data', chứ không phải là một bối cảnh đệ quy dựa trên cấu trúc của kiểu đó. Các quy tắc có ý nghĩa đối với 'Eq' vì mã được tạo ra chính nó là cấu trúc đệ quy. –

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