Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

makeFields fails for ExistentialQuantification and GADTs syntax #409

Closed
emchristiansen opened this issue Mar 9, 2014 · 3 comments
Closed

Comments

@emchristiansen
Copy link

makeFields in Control.Lens.TH fails for record types declared using ExistentialQuantification and GADTs syntax.
Tested with GHC 7.6.3 and current lens (I believe 4.0.5).
For example, the following fails with "verboseLenses: Expected the name of a record type".

data Foo a = (Num a) => Foo 
  { _fooBarL :: a
  }
makeFields ''Foo

This fails with the same error when using GADTs syntax.
I've also noticed silent failures when using makeLenses and makeClassy.

We should either fix the code or update the docs to reflect the limits of the TH methods.

@glguy
Copy link
Collaborator

glguy commented Mar 10, 2014

makeFields doesn't support a context before the constructor, which is usually related to existential quantification. In this case I expect you meant to write:

data Foo = forall a. Num a => Foo 
  { _fooBarL :: a
  }

and makeFields has needed documentation for a while. There's already a ticket for that if anyone wants to write the documentation.

makeLenses makes a best effort which ranges from Iso though Lens, Traversal, Fold, Getter, and nothing for each constructor depending on what makes sense. Silent "failure" is key since users will want the generated accessors for the constructors where it makes sense. The best that could be hoped for is this setter, which might be useful.

fooBarL :: Num a => Setter Foo Foo () a
fooBarL = setting (\f _ -> Foo (f ()))

@ekmett
Copy link
Owner

ekmett commented Mar 10, 2014

I'm rather against the non-law abiding Setter solution.

over fooBarL id /= id

It also closes off the "more correct but still broken" solution:

foo :: (Functor f, Num b) => (forall a. Num a => a -> f b) -> Foo -> f Foo

Unfortunately, you can't write combinators that can accept that version, which are reasonably parametric in Haskell, so all code working with it has to be written in direct style, and you can't compose them with (.), so I don't want to generate those either.

Also that version still isn't right as it makes the choice of b independent of the choice of a and it should be possible to pick b = a, but due to the ordering of the quantifiers it has to make its choice too early!

I think the right solution is to document that we can't provide lenses for existentially quantified fields, and to fix it so we supply lenses, traversals, getters and folds for the remaining fields if we can if we're skipping them just because of the context.

@glguy
Copy link
Collaborator

glguy commented Mar 10, 2014

Support for fields of constructors under a forall is added in 111341a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants