How to work around inability to use lenses with existential types?

existential-type, haskell, haskell-lens, lenses

Solution

In the worst case, you can always implement the lenses yourself without relying on Template Haskell at all.

For example, given a getter and a setter function for your type, you can create a lens using the `lens` function:

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

I believe this may not be the most performant option, but it's certainly the easiest.

I don't know how to do this for your case (or with existential types in general), but here's a trivial example using a record:

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

Hopefully this illustrates the idea well enough to apply to your code.

Problem

I am using Edward Kmett's lens library for the first time, and finding it rather nice, but I ran into a snag... The question at [1] explains that existential quantifiers disrupt makeLenses. I really rather want to use an existential with lenses in some fashion. As background, I have the class: ``` 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 ``` For the actual question, I want to have the type: ``` data AnyFile = forall file . File file => AnyFile { _anyFileAnyFile :: File } ``` And I want to be able to write something along the lines of: ``` instance File AnyFile where fromAnyFile (AnyFile file) = cast file fileType (AnyFile file) = fileType . anyFile path (AnyFile file) = path . anyFile provenance (AnyFile file) = provenance . anyFile ``` This doesn't work, for the reason explained in [1]. If I ask GHC for debugging information by compiling with `-ddump-splices`, I get: ``` Haskell/Main.hs:1:1: Splicing declarations makeLenses ''AnyFile ======> Haskell/Main.hs:59:1-20 ``` The splice itself is blank, which indicates to me that no declarations are produced by it. This part I expect and understand now that I have read [1]. What I would like to know is how I can do this - what might I do to work around the problem? What might I do to avoid swimming upstream on this? I would like to be able to access any part of my structures through a path of composed lenses, but because I have fields in other types with types such as `Set AnyFile`, I cannot do so unless I can access the content of `AnyFile` with a lens. [1] Existential quantifier silently disrupts Template Haskell (makeLenses). Why?

Original source