fslang-suggestions
fslang-suggestions copied to clipboard
Allow operators as active patterns
Allow operators as active patterns
I propose we allow to define operators as active patterns, so we'll be able to write code like this:
match x with
| a ++ b -> ...
or
let (a ++ b) = x
This can be defined like let (| ++ |) x = ...
Pros and Cons
The advantages of making this adjustment to F# are:
- More symmetry with operators used for construction.
- Consistency with list pattern matching for list-like and tuple-like things.
- More identifiers available for active patterns
The disadvantages of making this adjustment to F# are
- Possible complications in updating F# parser
Extra information
Estimated cost XS / S:
Related suggestions: none that I know
Affidavit (please submit!)
Please tick this by placing a cross in the box:
- [x] This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
- [x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
- [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.
Please tick all that apply:
- [x] This is not a breaking change to the F# language design
- [x] I or my company would be willing to help implement and/or test this
For Readers
If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.
What would happen to the existing pattern match operators |, & in that context?
@7sharp9 | is already not a valid custom operator, and & gives a warning that it shouldn't be used, so I guess it would be reasonable to forbid both of them as custom pattern operators.
I meant during the match, as &/| are already allowed.
It is hard for me to comment without understanding more about code where you'd use it.
It would help me if you'd had samples of before/after added to the suggestion.
On the syntax, if the semantics are the same as active patterns, I suggest this:
let (|a ++ b|) = x
Here are some cases where I miss this feature:
- List-like user types:
If I define a NonEmptyList<'t> and an operator, like ++ to concatenate a head and a tail, to do the opposite I need to define a named active pattern, like (Cons (x, xs)), but it would be nice to use the same operator for both operations.
let nlist = head ++ tail
...
let (Cons (head, _)) = nlist
as opposed to
let (head ++ _) = nlist
- Codecs:
A codec type can be constructed from an encoding function and a decoding function. I use the
<->operator for that which symbolizes a bidirectional function. Codecs can also be deconstructed into that pair of functions, unfortunately that operation should be more verbose and I should use a different name for that.
let codec = decoder <-> encoder
...
let (Codec (decoder, _)) = codec
as opposed to
let (decoder <-> _) = codec
In both cases, having the possibility to use the same operator to deconstruct leads to an API more consistent and therefore easier to use, as we don't have to remember two operations.
Contrast it with the :: operation for lists and the , operations for tuples and try to imagine how our code would look like without these operators being able to be used for deconstruction.
Interesting idea. I kind of like it 🙂. Not sure if I'd ever use it, but I can see the use here.
I'm not in favour of extending the role of user-definable symbolic operators in the language like this, into pattern matching. Just use an active pattern. As part of this, I'd kind of like to remove :: or make it type-directed.