2016-09-13 28 views
8

Xét đoạn mã sauGADT kiểu lập luận không được sử dụng để giải quyết typeclass

data Foo f where 
    Foo :: Foo Int 

class DynFoo t where 
    dynFoo :: Foo f -> Foo t 

instance DynFoo Int where 
    dynFoo Foo = Foo 

obsFoo :: (DynFoo t) => Foo f -> Foo t 
obsFoo = dynFoo 

useDynFoo :: Foo f -> Int 
useDynFoo (obsFoo -> Foo) = 1 

Trận đấu pattern trong useDynFoo nên hạn chế việc sử dụng các obsFoo có loại Foo f -> Foo Int, mà nên gây ra nó để tìm kiếm một thể hiện của DynFoo Int . Tuy nhiên, thay vào đó, nó tìm kiếm một thể hiện của DynFoo t cho không rõ t và tự nhiên không thành công.

No instance for (DynFoo t0) arising from a use of ‘obsFoo’ 
    The type variable ‘t0’ is ambiguous 

Tuy nhiên, nếu tôi thay đổi định nghĩa của useDynFoo để

useDynFoo :: Foo f -> Int 
useDynFoo (obsFoo -> (Foo :: Foo Int)) = 1 

Sau đó, nó đột nhiên hoạt động, mặc dù loại chữ ký của tôi là hoàn toàn không cần thiết.

Vì vậy, tại sao điều này xảy ra và làm cách nào tôi có thể sử dụng obsFoo mà không cần phải cung cấp chữ ký loại?

Trả lời

2

Đó là rõ ràng hơn nếu bạn viết nó ra với một case (xem mẫu được khá che khuất WRT dòng kiểu thông tin) rõ ràng:

useDynFoo :: Foo f -> Int 
useDynFoo foof = case obsFoo foof of 
    Foo -> 1 

Ở đây, các thông tin f ~ Int là hoàn toàn dễ tiếp cận cho số 1. Vâng, nhưng đó không phải là nơi chúng tôi cần thông tin này: chúng tôi cần nó tại obsFoo foof. Và thông tin không thể đạt được: các mẫu khớp GADT hoạt động như một "diode thông tin loại" hoàn chỉnh, tức là mọi thông tin từ bên ngoài có thể được sử dụng trong phạm vi phù hợp, nhưng không có thông tin từ bên trong có thể được sử dụng mà không có. (Vì lý do tốt rõ ràng, vì thông tin đó chỉ có thể được khẳng định trong thời gian chạy, khi bạn thực sự một constructor GADT để mang nó từ.)

Câu hỏi thú vị hơn là, tại sao nó có tác dụng nếu bạn thêm :: Foo Int Chữ ký? Vâng, đặc biệt là một sự kỳ quặc của mô hình xem. Hãy xem, những điều sau đây sẽ không công việc:

useDynFoo :: Foo f -> Int 
useDynFoo foof = case obsFoo foof of 
    (Foo :: Foo Int) -> 1 

Những thông tin này, như bạn nói chính mình, là hoàn toàn không cần thiết.

Tuy nhiên nó chỉ ra rằng mô hình quan điểm này thực sự là tương đương với việc đưa chữ ký trên các phần khác của vụ án:

useDynFoo :: Foo f -> Int 
useDynFoo foof = case obsFoo foof :: Foo Int of 
    Foo -> 1 

và điều này là khá một đôi giày khác nhau, bởi vì bây giờ Foo Int không phải là bên trong kết hợp mẫu GADT.

Tôi không biết tại sao dạng xem với chữ ký desugar như thế này, có lẽ để làm cho mẫu này rất có thể.

1

Loại chữ ký không thừa khi sử dụng GADT. Lưu ý điểm viên đạn cuối cùng của GHC Users Guide: GADTs

+4

Câu trả lời chỉ dành cho liên kết này, cần được mở rộng. Ngay bây giờ nó không giải thích nhiều. – chi

+0

Bạn cũng nên tránh liên kết đến "mới nhất", thích một phiên bản tài liệu cụ thể. – dfeuer

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