2012-05-07 34 views
5

Sau khi cố gắng sử dụng Data.Has, tôi đã viết code như sau:gia đình kiểu Haskell, sự hiểu biết thông báo lỗi

data Name = Name; type instance TypeOf Name = Text 
type NameRecord = FieldOf Name; 

tôi đã tìm thấy:

instance I NameRecord where 
    ... 

Ném một lỗi biên dịch, cụ thể là:

Illegal type synonym family application in instance

Trong đó:

012.
instance (NameRecord ~ a) => I a where 
    ... 

Biên dịch tốt.

Tôi tin rằng lỗi có liên quan đến this vé trong GHC, được đánh dấu là không hợp lệ.

Việc đối phó với vé nói:

I am not sure what you are suggesting. We cannot automatically transform

instance C (Fam Int) -- (1) 

into

instance (Fam Int ~ famint) => C famint -- (2) 

This works if there is only one instance, but as soon as there are two such instances, they always overlap.

Maybe you are suggesting that we should do it anyway and programmers should just take the implicit transformation into account. I don't think that this is a good idea. It's confusing for very little benefit (as you can always write the transformed instance yourself with little effort).

Ai đó có thể xây dựng trên giải thích này, có lẽ với một số mẫu mã nơi (1) thất bại nhưng (2) không, và tại sao?

Trả lời

4

Trường hợp (1) không thành công nhưng (2) không nhỏ; vì loại từ đồng nghĩa (type ExampleOfATypeSynonym = ...) không được phép vào tờ khai ví dụ, nhưng họ được cho phép trong những hạn chế, bất kỳ tình huống mà bạn chỉ có một dụ như thế này:

-- (1) 
class Foo a 
type Bla =() 
instance Foo Bla 

... có thể được chuyển đổi thành:

-- (2) 
class Foo a 
type Bla =() 
instance (a ~ Bla) => Foo a 

Lý do duy nhất tại sao (1) không thành công vì loại từ đồng nghĩa không được phép trong khai báo cá thể, và đó là do loại từ đồng nghĩa giống như chức năng loại: chúng cung cấp ánh xạ một chiều từ tên loại đến tên loại, vì vậy nếu bạn có type B = Ainstance Foo B, không rõ ràng rằng một thể hiện của Foo A được tạo ra để thay thế. Quy tắc tồn tại để bạn phải viết instance Foo A thay vào đó để làm rõ rằng rằng là loại thực sự nhận được cá thể.

Việc sử dụng loại gia đình không liên quan trong ngữ cảnh này, bởi vì vấn đề là bạn đang sử dụng loại đồng nghĩa loại, loại NameRecord. Bạn cũng phải ghi nhớ rằng nếu từ đồng nghĩa loại được loại bỏ và thay thế bằng FieldOf Name trực tiếp, biên dịch sẽ vẫn không thành công; đó là vì "loại gia đình" chỉ là phiên bản nâng cao của các từ đồng nghĩa loại, do đó, FieldOf Name cũng là "loại từ đồng nghĩa" cho Name :> Text trong ngữ cảnh này. Bạn phải sử dụng một họ dữ liệu và một cá thể dữ liệu thay vào đó để có được một liên kết "hai chiều".

Thông tin thêm về họ dữ liệu có thể được tìm thấy trong GHC documentation.


Tôi nghĩ bạn có nghĩa là "... ở đâu (2) không thành công nhưng (1) không ..."

Hãy tưởng tượng rằng chúng tôi có một kiểu lớp như vậy:

class Foo a where 
    foo :: a 

Bây giờ, bạn có thể viết các trường hợp như vậy:.

instance Foo Int where 
    foo = 0 

instance Foo Float where 
    foo = 0 

main :: IO() 
main = print (foo :: Float) 

này hoạt động như một mong chờ Tuy nhiên, nếu bạn chuyển đổi mã này thành:

{-# LANGUAGE FlexibleInstances, TypeFamilies #-} 
class Foo a where 
    foo :: a 

instance (a ~ Int) => Foo a where 
    foo = 0 

instance (a ~ Float) => Foo a where 
    foo = 0 

main :: IO() 
main = print (foo :: Float) 

Nó không biên dịch; nó hiển thị lỗi:

test.hs:5:10: 
    Duplicate instance declarations: 
     instance a ~ Int => Foo a -- Defined at test.hs:5:10-27 
     instance a ~ Float => Foo a -- Defined at test.hs:8:10-29 

Vì vậy, đây là ví dụ bạn hy vọng đang tìm kiếm. Bây giờ, điều này chỉ xảy ra nếu có nhiều hơn một phiên bản của Foo sử dụng thủ thuật này. Tại sao vậy?

Khi GHC phân giải các loại lớp, nó chỉ nhìn vào đầu khai báo cá thể; nghĩa là nó bỏ qua mọi thứ trước =>. Khi nó đã chọn một thể hiện, nó "cam kết" với nó, và kiểm tra các ràng buộc trước => để xem chúng có đúng không. Vì vậy, lúc đầu nó thấy hai trường hợp:

instance Foo a where ... 
instance Foo a where ... 

Nó rõ ràng là không thể để quyết định dụ để sử dụng dựa trên các thông tin này một mình.

+0

Không quan tâm, bạn có biết liệu phương pháp giải quyết các loại lớp của GHC có phải là một quyết định thiết kế rõ ràng không? Và nếu vậy, lý do cho nó? (Hoặc có thể thay thế quá phức tạp để thực hiện một cách rõ ràng?) – huon

+3

Lý do cho nó là Báo cáo Haskell yêu cầu nó hoạt động như thế này. Lý do cho ** rằng ** là nếu nó không hoạt động như thế này, thì phải có một thuật toán đưa ra một heuristic cho "một loại phù hợp với một ràng buộc như thế nào;" bạn phải tranh luận "Vâng, loại này phù hợp với cá thể lớp này, nhưng trường hợp khác phù hợp hơn nhiều vì {ít ràng buộc, khoảng cách giảm ngắn hơn, ...}." Nó có thể có thể phát triển như một heuristic, nhưng nó sẽ phá vỡ Open World Assumption là một khái niệm quan trọng khi nói đến các lớp loại. – dflemstr

+0

Hãy tưởng tượng 'instance string ~ a => Foo a' và' instance a ~ [b] => Foo a'. Đó là một ví dụ về các trường hợp bạn cần một thuật toán để giải quyết 'Foo [Char]'. – dflemstr

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