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

TH Generation of LabelOptic instances for prisms on sum-types #354

Open
nikita-volkov opened this issue Sep 15, 2020 · 4 comments
Open

TH Generation of LabelOptic instances for prisms on sum-types #354

nikita-volkov opened this issue Sep 15, 2020 · 4 comments

Comments

@nikita-volkov
Copy link

Which for the following type:

data ApiError =
  InvalidDataApiError |
  RejectedApiError Text |
  UnauthorizedApiError Int Text

would generate instances like the following:

instance LabelOptic "invalidData" A_Prism ApiError ApiError () () where
  labelOptic =
    prism' (const InvalidDataApiError)
      \ case
        InvalidDataApiError -> Just ()
        _ -> Nothing

instance LabelOptic "rejected" A_Prism ApiError ApiError Text Text where
  labelOptic =
    prism' RejectedApiError
      \ case
        RejectedApiError a -> Just a
        _ -> Nothing

instance LabelOptic "unauthorized" A_Prism ApiError ApiError (Int, Text) (Int, Text) where
  labelOptic =
    prism' (\ (a, b) -> UnauthorizedApiError a b)
      \ case
        UnauthorizedApiError a b -> Just (a, b)
        _ -> Nothing

Allowing to address this sum-type like this:

> preview #rejected (RejectedApiError "alsdkjf")
Just "alsdkjf"

Benefits

  1. Makes prisms conform to the same convention as of record labels.
  2. Avoids polluting the namespace with generated functions.
  3. Avoids the awkwardness of the _PrismName naming convention.
@adamgundry
Copy link
Member

This is essentially what makePrismLabels does, isn't it? Modulo some questions about how to map constructor names onto label names...

@nikita-volkov
Copy link
Author

How about having a declareOpticLabels function, which would declare instances for both sum-types and records?

@arybczak
Copy link
Collaborator

Declaring a type within declateFieldLabels and then calling makePrismLabels after does the job (see #355).

Interesting proposition. I imagine that generation of optics for both fields and constructors for a data type is useful mostly when you have partial field accessors, but declare flavor gets rid of unsafe partiality by not exposing accessors and giving you affine traversals instead.

If only we had viable (i.e. not conflicting with strict fields) way to construct values of such types with optics...

@nikita-volkov
Copy link
Author

I've been suggesting it so that there'd be a single function to call no matter what structure you're dealing with. More so, it would allow to pass a bunch of type declarations (your whole domain model ideally) into a single call of declareOpticLabels.

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

No branches or pull requests

3 participants