How to deal with the inability to use lenses with existential types?

This is my first time using the Edward Kmett library for lenses , and I find it pretty nice, but I ran into a problem ...

A question in [1] explains that existential quantifiers violate makeLenses. I really prefer to use the existential lens in some way.

As a background, I have a 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 a type:

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

And I want to write something line by line:

 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 does not work for the reason described in [1]. If I ask the GHC to debug information by compiling with -ddump-splices , I get:

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

Splicing itself is empty, which indicates that no declarations are created. This is the part that I expect and understand now that I have read [1].

What I would like to know is how I can do this - what can I do to solve this problem? What can I do to not swim upstream? I would like to be able to access any part of my structures along the path of folded lenses, but since I have fields in other types with types such as Set AnyFile , I cannot do this if I cannot access the contents of AnyFile with a lens .

[1] The existential quantifier silently destroys the Haskell (makeLenses) pattern. Why?

+6
source share
1 answer

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

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

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

I believe that this is not the most effective option, but it is certainly the easiest.

I don’t know how to do this for your case (or with existential types in general), but here is a trivial example using the notation:

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

Hope this illustrates an idea sufficient to apply to your code.

+7
source

Source: https://habr.com/ru/post/951043/


All Articles