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

Transform patterns within a subscope #9

Open
gelisam opened this issue Feb 25, 2018 · 5 comments
Open

Transform patterns within a subscope #9

gelisam opened this issue Feb 25, 2018 · 5 comments
Labels
enhancement New feature or request

Comments

@gelisam
Copy link
Owner

gelisam commented Feb 25, 2018

Consider the following code:

listMaybeBools :: [Maybe Bool]
listMaybeBools = (Just <$> [True, False])
              ++ [Nothing]

There are two ways to make this surjective-friendly. We could list the three values separately:

listMaybeBools :: [Either Bool Bool]
listMaybeBools = $$(surjective
  [||\covers -> [ covers $ \(Just True)  -> Just True
                , covers $ \(Just False) -> Just False
                , covers $ \Nothing      -> Nothing
               ]
  ||])

Or we could split out the [True, False] bit into its own surjective-friendly definition:

listBools :: [Bool]
listBools = $$(surjective
  [||\covers -> [ covers $\True  -> True
                , covers $ \False -> Just False
                ]
  ||])

listMaybeBools :: [Either Bool Bool]
listMaybeBools = $$(surjective
  [||\covers -> ((\x -> covers $ \(Just _) -> Just x) <$> listBools)
             ++ [covers $ \Nothing -> Nothing]
  ||])

I personally like this second approach, but surjective shouldn't be in the business of recommending a coding style. To support the style of the original definition, we'd need to transform small patterns into bigger patterns:

listMaybeBools :: [Either Bool Bool]
listMaybeBools = $$(surjective
  [||\covers -> (Just <$> (transform covers $ \x -> \(Just x) -> \covers' -> [ covers' $ \True  -> True
                                                                            , covers' $ \False  -> False
                                                                            ]))
             ++ [covers $ \Nothing -> Nothing]
  ||])

Semantically, transform is another macro which, like surjective, gathers the calls to covers within its scope. Then, it transforms them (in this case from x to Just x), and passes them on to the surrounding surjective macro, who will gather both the patterns produced by transform (in this case Just True and Just False) and the other pattern defined outside of transform (in this case Nothing).

Since covers has type Covers a, transform must bind its own covers' function, of type Covers Bool.

Suggested by @rpglover64 in the same reddit comment as #8's suggestion.

@gelisam gelisam added the enhancement New feature or request label Feb 25, 2018
@rpglover64
Copy link
Collaborator

transform covers $ \x -> \(Just x) -> [...]

In the comment, I was careful that the second appearance of the variable was in an expression context, not in a pattern context; if both uses are in a pattern, the TH won't have the same name for both variables.

@gelisam
Copy link
Owner Author

gelisam commented Feb 25, 2018

I see! I'm a bit wary about using the (\x -> Just x) syntax because this would require converting an expression to a pattern, which would require slightly more maintenance as more patterns are added to the language. Hawk keeps getting broken as new syntax is added to haskell-src-exts for example, which is why I used the magic from Control.Lens.Plated this time.

@gelisam
Copy link
Owner Author

gelisam commented Feb 25, 2018

While the Names of the xs are indeed different, turns out their OccNames are the same.

@rpglover64
Copy link
Collaborator

Hawk keeps getting broken as new syntax is added to haskell-src-exts for example

Would th-abstaction help?

turns out their OccNames are the same

ehh... I guess? That strikes me as more fragile, but I don't do much metaprogramming.

@gelisam
Copy link
Owner Author

gelisam commented Feb 25, 2018

th-abstraction indeed looks helpful for the kind of problems I am describing, but it looks like they aren't supporting patterns nor expressions yet.

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

No branches or pull requests

2 participants