-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Proposal: Conjunctive and Disjunctive Patterns #6235
Comments
I really like the idea but don't really care for the syntax. I'd prefer that the standard "Conjunctive" patterns seem like they should be relatively easy by themselves since each pattern would only introduce its own variables and there is no concern about pattern precedence. "Disjunctive" patterns add the additional requirement to the compiler to ensure that the variables would all be definitely assigned and inferred (if not explicitly set) to the same type. I'm not saying that's a problem and you do already mention it, just reiterating the point. I also think that since logical or operations have a lower precedence than logical and operations that you'd want to introduce parenthesis in order to allow the developer to force order of operations. var result = match obj {
// matched if A is matched and if either B or C is also matched
case A(var x) && (B(var y) || C(var y)): x * y,
// matched if both B and C are matched, or if just A is matched
case A(*) && B(*) || C(*): x + y
...
}; |
To note, I think C# developers are really going to expect this kind of functionality especially since they can use pattern matching directly in if (obj is A(var x) && (obj is B(var y) || obj is C(var y))) {
Console.WriteLine($"( {x}, {y} )");
} |
@HaloFour |
@HaloFour I'm not sure about using logical and/or operators in this context. Since logical operators themselves are not allowed in the patterns, this would be confusing (or even ambiguous when used with |
That it would. But if you changed the second I wouldn't argue for altering that behavior in normal Boolean expressions. However I do think that pattern matching with let result =
match point with
| (0, x) | (5, x) -> x
| (10, x) | (15, y) -> x // ERROR: The two sides of this 'or' pattern bind different sets of variables
| _ -> 0 @alrz Maybe not, but it seems weird to have two ways to express Boolean logic and they apply to completely different places. Can't say I care for |
Worth to mention, the syntax of |
@HaloFour That doesn't make sense, the whole expression containing |
@alrz Which is why I mentioned only worrying about that in |
Patterns may contain (almost general) expressions (as long as they resolve to a constant). Generalizing patterns to look like expressions may introduce an inherent ambiguity. |
Irrelevant, but will this be supported? // assuming
public static Mult operator *(Expr a, Expr b) => Mult(a, b);
// then
expr match( case Expr a * Expr b : ... )
// instead of
expr match( case Mult( a , b ) : ... ) |
@alrz That doesn't even syntactically look like a pattern (or an expression); how could it work? |
@gafter I take it as a no then. |
@alrz As you wish, "no" it is. 😉 |
@gafter FYI, it is a pattern in Mathematica. |
Really? And how does Mathematica associate the implementation of your overloaded |
Really. Well it hasn't operator overloading, Everything is a function: |
Actually, I mistranslated my pattern as an expression (of a pattern). Instead of: if (obj is A(var x) && (obj is B(var y) || obj is C(var y))) {
Console.WriteLine($"( {x}, {y} )");
} it should be: if (obj is (A(var x) && (B(var y) || C(var y)))) {
Console.WriteLine($"( {x}, {y} )");
} I am using the |
You are using type intersection (#4586) I presume, I think that is a totally new kind of type and now you're introducing it as a pattern. I have no idea how this would work. PS: Sorry I think that is not. That's because you have suggested |
@alrz Not at all, they could be any custom patterns that are in scope that can be applied to |
I think constant-pattern should be part of complex-pattern so that PS: If disjunction is not planned currently, still, match-expression should support multiple-cases to be closer to its statement form — in that case presence of comma would be even more confusing. |
The thing to the right of your |
@alrz Not sure why |
@gafter You're correct. I don't know what syntax would work the best. Either way it's the concept in which I'm more interested, the ability to apply Boolean operators to patterns supporting operator precedence as well as support for applying the same identifier to multiple variable patterns where it can be guaranteed by the compiler that it would result in exactly one assignment. Effectively, everything F# does. 😄 |
@HaloFour I don't think that even F# supports parens in patterns in order to change the precedence. |
@alrz I think you're right. The docs do demonstrate combining AND and OR patterns. |
@alrz Actually, rereading F#'s supported patterns it does have "Parenthesized Pattern" which is specifically for defining the associativity and precedence of the patterns: let countValues list value =
let rec checkList list acc =
match list with
| (elem1 & head) :: tail when elem1 = value -> checkList tail (acc + 1)
| head :: tail -> checkList tail acc
| [] -> acc
checkList list 0
let result = countValues [ for x in -10..10 -> x*x - 4 ] 0
printfn "%d" result |
@HaloFour Neat. I'm not against it anyway. |
Moved to dotnet/csharplang#118 |
(Extracted from #5402 as it was orthogonal to the subject)
The following is based on the syntax proposed in #206:
A conjunctive-pattern matches the pattern input against two patterns, if either failed, pattern fails.
In a disjunctive-pattern, the pattern input is matched against the first pattern. If that fails, the pattern input is matched against the second pattern. Both patterns must bind the same set of variables with the same types.
EDIT: For OR pattern we can use #1419 rules to select the most common type between both sides.
The text was updated successfully, but these errors were encountered: