Allow separate pattern synonym construction types
Motivation
Usually today when I go to write a pattern synonym that has non-trivial constraints on construction and pattern matching I wind up having to clutter user facing code with two patterns names and an extra combinator.
Example:
I build the bidirectional pattern synonym that contains all the constraints:
pattern JSON :: (FromJSON a, ToJSON a) => () => a -> String
pattern JSON a <- (preview _JSON -> Just a) where
JSON a = _JSON # a
but because that is so restrictive, I wind up having to supply a unidirectional pattern and combinator for the other two halves of the transformation, lest I require the user to pass me (possibly quite inefficient) dictionaries for unused directions.
pattern JSON' :: ToJSON a => a -> String
pattern JSON a <- ...
jSON :: FromJSON a => a -> String
jSON = ...
Proposal
I'd really much prefer to be able to split these two sets of constraints up in the explicit bidirectional pattern syntax:
pattern JSON :: ToJSON a => a -> String
pattern JSON a <- ... where
JSON :: FromJSON a => a -> String
JSON a = ...
The outer signature should keep its Required => Provided => ...
context as usual, but the signature of the constructor could be specialized. Now I only have to take one user facing name and the API is much cleaner with no spurious unnecessary constraints being passed. In the absence of such a signature JSON used as a constructor would default to Required => ...
as usual.
Outside of JSON I have examples involving BDD construction, serialization, Read/Show
and pretty much anything where the To
and From
directions are split into separate classes.