2013-08-05 6 views
6

Я использую объектива библиотеки Эдварда Kmett в первый раз, и найти его довольно хорошо, но я столкнулся с корягу ...Как работать с неспособностью использовать объективы с экзистенциальными типами?

вопроса на [1] объясняет, что экзистенциальные кванторы нарушить makeLenses. Я действительно предпочитаю использовать экзистенциальный объектив каким-то образом.

В фоновом режиме, у меня есть класс:

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 

Для фактического вопроса, я хочу, чтобы иметь тип:

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

И я хочу, чтобы иметь возможность написать что-то вдоль линий от:

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

Это не работает по причине, описанной в [1]. Если я спрошу GHC для отладки информации путем компиляции с -ddump-splices, я получаю:

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

Сам сращивания является пустым, который указывает мне, что никакие декларации не производятся ею. Эта часть я ожидаю и понимаю теперь, что я прочитал [1].

Что я хотел бы знать, как я могу это сделать - что я могу сделать, чтобы решить эту проблему? Что я могу сделать, чтобы не плавать вверх по течению? Я хотел бы иметь возможность доступа к любой части моих структур по пути сложенных объективов, но поскольку у меня есть поля в других типах с такими типами, как Set AnyFile, я не могу этого сделать, если не могу получить доступ к содержимому AnyFile с объективом.

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

+0

Просто для кого-то, кто задавался вопросом, что я сделал, было использовать это предложение ниже; определение должно быть «объективом» (\ (файл AnyFile) -> file) (\ _ значение -> значение AnyFile) '. –

ответ

7

В худшем случае, вы всегда можете реализовать линзы самостоятельно, не полагаясь на Template Haskell вообще.

Например, если геттер и сеттер функцию для вашего типа, вы можете создать объектив с помощью lens функции:

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

Я считаю, что это не может быть самым производительным вариантом, но это, безусловно, простой.

Я не знаю, как это сделать для вашего случая (или экзистенциальных типов в целом), но вот простой пример, используя запись:

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

Надеемся, что это иллюстрирует идею достаточно хорошо, чтобы применить к вашему коду.

+0

Хм ... Я не знал о функции объектива. Спасибо! Документы скорее, er, большие. :) Я пытаюсь сделать что-то сейчас, и я буду принимать ответ, если это произойдет. :) –

+1

Тип объектива, по крайней мере, в моей версии, выглядит как «Функтор f => (s -> a) -> (s -> b -> t) -> (a -> fb) -> s -> ft'. Хорошо. Похоже, что-то вроде продолжения, проходящего мимо вещей, я, наверное, могу это понять ... –

+0

О, я вижу. Правильно. Мне нужны только первые два параметра, потому что остальные являются частью самого объектива ... Возможно, документы могут объяснить, что для меня 's'. –