2013-08-05 36 views
6

Tôi đang sử dụng ống kính thư viện Edward Kmett cho lần đầu tiên, và tìm thấy nó khá đẹp, nhưng tôi chạy vào một snag ...Làm thế nào để làm việc xung quanh không có khả năng sử dụng ống kính với các loại tồn tại?

Câu hỏi tại [1] giải thích rằng quantifiers hiện sinh phá vỡ makeLenses. Tôi thực sự muốn sử dụng một tồn tại với ống kính trong một số thời trang.

Là nền, tôi có lớp:

class (TextShow file, Eq file, Ord file, Typeable file) => File file where 
    fromAnyFile :: AnyFile -> Maybe file 
    fileType :: Simple Lens file FileType 
    path :: Simple Lens file Text.Text 
    provenance :: Simple Lens file Provenance 

Đối với câu hỏi thực tế, tôi muốn có các loại:

data AnyFile = forall file . File file => AnyFile { _anyFileAnyFile :: File } 

Và tôi muốn để có thể viết một cái gì đó dọc theo dòng của:

instance File AnyFile where 
    fromAnyFile (AnyFile file) = cast file 
    fileType (AnyFile file) = fileType . anyFile 
    path (AnyFile file) = path . anyFile 
    provenance (AnyFile file) = provenance . anyFile 

Điều này không hiệu quả, vì lý do được giải thích trong [1]. Nếu tôi hỏi GHC cho thông tin gỡ lỗi bằng cách biên dịch với -ddump-splices, tôi nhận được:

Haskell/Main.hs:1:1: Splicing declarations 
    makeLenses ''AnyFile ======> Haskell/Main.hs:59:1-20 

Các mối nối chính nó là trống, mà chỉ ra cho tôi rằng không có tờ khai được sản xuất bởi nó. Phần này tôi mong đợi và hiểu bây giờ tôi đã đọc [1].

Điều tôi muốn biết là cách tôi có thể thực hiện việc này - tôi có thể làm gì để khắc phục sự cố này? Tôi có thể làm gì để tránh bơi ngược dòng về điều này? Tôi muốn có thể truy cập vào bất kỳ phần nào của cấu trúc thông qua một ống kính sáng tác, nhưng vì tôi có các loại khác với các loại như Set AnyFile, tôi không thể làm như vậy trừ khi tôi có thể truy cập nội dung của AnyFile bằng ống kính.

[1] Existential quantifier silently disrupts Template Haskell (makeLenses). Why?

+0

Chỉ cần cho bất cứ ai tự hỏi, những gì tôi đã làm là sử dụng gợi ý dưới đây; định nghĩa cần phải là 'thấu kính (\ (tập tin AnyFile) -> tập tin) (\ _ giá trị -> giá trị AnyFile)'. –

Trả lời

7

Trong trường hợp xấu nhất, bạn luôn có thể thực hiện các ống kính chính mình mà không dựa vào Template Haskell ở tất cả.

Ví dụ, đưa ra một phương thức getter và một hàm setter cho loại hình của bạn, bạn có thể tạo một ống kính sử dụng lens chức năng:

lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b 

Tôi tin rằng điều này có thể không phải là lựa chọn performant nhất, nhưng nó chắc chắn là dễ nhất.

Tôi không biết làm thế nào để làm điều này đối với trường hợp của bạn (hoặc với các loại hiện sinh nói chung), nhưng đây là một ví dụ nhỏ bằng một kỷ lục:

data Foo = Foo { _field :: Int } 
foo = lens _field (\ foo new -> foo { _field = new }) 

Hy vọng rằng đây minh họa các ý tưởng cũng đủ để áp dụng vào mã của bạn.

+0

Hmm ... Tôi không biết về chức năng của ống kính. Cảm ơn bạn! Các tài liệu khá, er, lớn. :) Tôi đang cố gắng để làm một cái gì đó làm việc ngay bây giờ, và sẽ chấp nhận câu trả lời nếu nó. :) –

+1

Loại ống kính, ít nhất trong phiên bản của tôi, có vẻ là 'Functor f => (s -> a) -> (s -> b -> t) -> (a -> fb) -> s -> ft'. Đuợc. Có vẻ như một thứ gì đó tiếp tục trôi qua, tôi có thể đoán ra nó ... –

+0

Ồ tôi hiểu rồi. Đúng. Tôi chỉ cần hai tham số đầu tiên bởi vì những thông số còn lại là một phần của chính ống kính ... Có lẽ các tài liệu có thể giải thích 's' là gì đối với tôi. –