2013-08-05 14 views
6

Używam obiektywu bibliotekę Edwarda Kmett jest po raz pierwszy, a znalezienie go dość ładne, ale wpadłem na szkopuł ...Jak radzić sobie z niemożnością użycia soczewek z typami egzystencjalnymi?

pytaniem na [1] wyjaśnia, że ​​kwantyfikatory egzystencjalne zakłócić makeLenses. Naprawdę wolę używać egzystencji z soczewkami w pewien sposób.

jako tło, mam klasę:

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 

za rzeczywiste pytanie, chcę mieć typ:

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

I chcę, aby móc napisać coś wzdłuż linii z:

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

To nie działa, z powodów wyjaśnionych w [1]. Jeśli pytam GHC do informacji diagnostycznych kompilując z -ddump-splices, otrzymuję:

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

Sam splice jest puste, co oznacza dla mnie, że żadne deklaracje są produkowane przez nią. W tej części oczekuję i rozumiem teraz, że przeczytałem [1].

Chciałbym wiedzieć, jak mogę to zrobić - co mogę zrobić, aby obejść problem? Co mogę zrobić, aby uniknąć płynięcia pod prąd? Chciałbym móc uzyskać dostęp do dowolnej części moich struktur poprzez ścieżkę złożonych soczewek, ale ponieważ mam pola w innych typach takich jak Set AnyFile, nie mogę tego zrobić, chyba że mogę uzyskać dostęp do zawartości obiektywu za pomocą AnyFile.

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

+0

Dla każdego, kto zastanawia się, co zrobiłem, skorzystałem z sugestii poniżej; definicja musi być 'soczewka (\ (plik AnyFile) -> plik) (\ _ wartość -> wartość AnyFile)'. –

Odpowiedz

7

W najgorszym wypadku zawsze można realizować samodzielnie soczewki bez polegania na Template Haskell w ogóle.

Na przykład, biorąc pod uwagę getter i setter funkcji dla danego typu, można utworzyć soczewki za pomocą lens funkcję:

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

Wierzę, że to nie może być rozwiązaniem najbardziej wydajnych, ale to na pewno najłatwiejszy.

Nie wiem, jak to zrobić w Twoim przypadku (lub z rodzaju egzystencjalnych w ogóle), ale tu jest trywialny przykład przy użyciu rekordu:

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

Mam nadzieję, że ten ilustruje ideę na tyle dobrze, aby zastosować do twojego kodu.

+0

Hmm ... Nie wiedziałem o funkcji obiektywu. Dziękuję Ci! Dokumenty są raczej, er, duże. :) Próbuję teraz sprawić, by coś działało i zaakceptuję odpowiedź, jeśli tak się stanie. :) –

+1

Typ obiektywu, przynajmniej w mojej wersji, wygląda na "Funktor f => (s -> a) -> (s -> b -> t) -> (a -> fb) -> s -> ft'. W porządku. Wygląda na coś, co może być kontynuacją, prawdopodobnie mogę to rozgryźć ... –

+0

Och, widzę. Dobrze. Potrzebuję tylko dwóch pierwszych parametrów, ponieważ pozostałe są częścią samego obiektywu ... Może doktorzy mogą wyjaśnić, co to jest dla mnie. –

Powiązane problemy