Open cgranade opened 3 years ago
<-
" you meant
"matches the pattern on the right of ->
".function Bad<'T>(in : 'T) : String
I see that in
{ after (
} is highlighted the same way as the keywords. This makes me suspect that either you really meant a keyword in
there, or the variable named in
can conflict with a keyword. Any comments about that would help.Maybe<Int>
, Some(..)
, and None
are not defined. I know those were mentioned in Discriminated Unions (that you refer to), but Discriminated Unions is just a related proposal, not a proposal yours is based on. So I'm not sure if you mean the same as that proposal or not. And even after having read that proposal I feel that Some(..)
and None
are still not defined (are black boxes for me).Mapped(Complex(_, 0.0), positiveCoefficients)
you meant
Mapped(Complex(_, 0.0), realCoefficients)
.
Otherwise I feel that positiveCoefficients
is undefined.
- I assume that with "matches the pattern on the right of
<-
" you meant "matches the pattern on the right of->
".
Thanks for catching, fixed that typo.
- In a fragment
function Bad<'T>(in : 'T) : String
I see thatin
{ after(
} is highlighted the same way as the keywords. This makes me suspect that either you really meant a keywordin
there, or the variable namedin
can conflict with a keyword. Any comments about that would help.
The in
identifier is reserved in Q# when using C# code generation; clarified by changing to input
.
- FYI: https://github.com/microsoft/QuantumLibraries/416 not found (error 404). Two occurrences.
Fixed.
- FYI: I feel that listings in "Example 3" section are longer than enough to illustrate the concept.
I feel that the value of choosing real-world examples from the actual decompositions used in our targeting packages is worth having a bit of a longer example. These translations are a bit messy at the moment due to the lack of some kind of switch or match, such that they make great usecases for a feature of this form.
- (Maybe I'm not familiar with evident Q# concepts, I apologize if that's the case) FYI: I feel that in "Example 4" the concepts of
Maybe<Int>
,Some(..)
, andNone
are not defined. I know those were mentioned in Discriminated Unions (that you refer to), but Discriminated Unions is just a related proposal, not a proposal yours is based on. So I'm not sure if you mean the same as that proposal or not. And even after having read that proposal I feel thatSome(..)
andNone
are still not defined (are black boxes for me).
As per the qsharp-language process, new language features start off as suggestions (represented by GitHub Issues), then proceed to be expanded into full proposals (represented by GitHub Pull Requests). Moreover, Example 4 is explicitly under a section that discusses how this suggestion would work with other suggestions and proposals — that section of the suggestion templated is intended to demonstrate how different suggestions work together, such that Examples 4 and 5 aren't truly standalone in that sense.
In any case, I've edited to clarify a little bit, and to point to the definition from https://github.com/microsoft/qsharp-language/issues/51 of Maybe<'T>
as newtype Maybe<'T> = Some('T) | None()
. As described at #51, Some<'T>(item0 : 'T) : Maybe<'T>
and None<'T>() : Maybe<'T>
are the two case constructors for the Maybe<'T>
discriminated union, similar to the Option<T>
DU in Rust, the Option<'a>
DU in F#, the Option[T]
type hint in Python, the Maybe T
DU in Haskell, and the Nullable<T>
struct in C#.
- FYI: I suspect that in Example 5 with fragment
Mapped(Complex(_, 0.0), positiveCoefficients)
you meantMapped(Complex(_, 0.0), realCoefficients)
. Otherwise I feel thatpositiveCoefficients
is undefined.
Thanks for catching; I had modified the name for clarity at one point and missed a spot when doing so.
@kuzminrobin @cgranade Thank you both for already starting a more detailed discussion here. The general idea is that the bar for submitting a suggestion should be relatively low, and in that sense I do explicitly not want that these suggestions get too long or too detailed. It is good to point out what requires further clarification in a potential proposal, but these things should not be added to the suggestion itself. We will give feedback on whether or not we think this is something that is worth fleshing out further based on a more or less minimal description. This particular suggest is already a bit long for my taste. :)
This particular suggest is already a bit long for my taste. :)
I'll take the responsibility for that one... I got a bit excited thinking about the different ways to use matching and may have gotten a bit carried away. Sorry about that...!
Suggestion
This suggestion proposes to add patterns to Q#, and to allow patterns to be used in deconstructing and matching values.
Considerations
The Q# language does not currently have a way of denoting that an action should be taken or a value should be computed from a list of closely related conditional expressions, similar to the
switch
ofcase
statements common to many imperative languages. In absentia such a feature, operations that make use of techniques such as lookup tables can become unwieldy, such as seen in https://github.com/microsoft/QuantumLibraries/issues/409.To resolve this in a way that also builds a path towards adopting more functional-inspired features in the future, this suggestion would introduce
match
expressions that allow breaking down the various cases of a given value by deconstructing that value into patterns. Where side effects are necessary and/or desirable, such that an expression form is not appropriate, this suggestion would also introduce a newif let
statement (similar to existing constructs in Rust and C#) that allows conditioning the execution of a block of statements on whether or not a given value matches a pattern.The design of this suggestion is intended to present patterns as a generalization of existing Q# concepts, such as deconstructing assignments, and to allow for the future growth of Q# in a consistent and coherent fashion.
Context
This suggestion generalizes the existing deconstruction feature, allowing for deconstructing more complicated patterns. In addition, this change would make it easier to develop additional Q# language features such as discriminated unions (see https://github.com/microsoft/qsharp-language/issues/51).
Related features in other languages:
Related Q# proposals and suggestions:
Kinds of patterns
We say that a pattern
pattern
is irrefutable for a type'T
if all possible values of type'T
matchpattern
. A pattern that is not irrefutable is refutable. A list of patternspattern1
,pattern2
, ... is exhaustive for a value of type'T
ifpattern1 | pattern2 | ...
is irrefutable for'T
.Kinds of patterns and pattern operators that may be worth considering:
_
), matches any value.pattern as name
), matchespattern,
but captures the value as a new immutable binding. As a shorthand,name
on its own acts as_ as name
; this can always be disambiguated, since arbitrary expressions cannot be used as patterns.(pattern1, pattern2, ...)
), matches values of a given arity, where each part of a value matches the corresponding pattern.pattern1 | pattern2 | ...
), matches any value that matchespattern1
,pattern2
, or so forth.()
,100L
,42
,3.14
,PauliX
,Zero
, or"foo"
): matches only the exact value of the given literal.(Real -> pattern, Imag -> _)
): matches named items of a UDT.Complex(0.0, _)
): similar to the tuple pattern, but matches on the unwrapped value of a UDT constructor. Possibly redundant with named item patterns, but is less explicit.[]
): matches only the empty array of a given type.[0 -> pattern1, 1... -> pattern2]
): matches when an index or range is valid, and when subscripting the value by the given index or range matches the pattern on the right of->
.[pattern1, pattern2]
): matches an array of the exact given length when each pattern is individually matched._ as foo when foo > 40
): matches only when a Boolean condition is met.Note that this list explicitly excludes anything that would cause reification of type information at runtime. For example, a type pattern cannot be used to refine an unconstrained generic:
This suggestion also excludes any consideration of F#-style active patterns,
Using patterns
This suggestion would extend Q# to allow using patterns in three distinct contexts:
let
,for
,use
, orborrow
statements).if let
, similar to Rust'sif let
statement and C#'sif (... is pattern)
statement).match
expression, similar to F#'s and Rust'smatch
, and to C#'sswitch
expressions).Examples
Example 1: Do something for each different Pauli operator.
Example 2: Define multiplication between Klein group elements (similar to group product and inverse definitions in https://github.com/microsoft/QuantumLibraries/issues/409).
Example 3: Apply different decompositions based on the number of controls.
Examples using other proposed and suggested Q# enhancements
Example 4: Using patterns with type-parameterized UDT and discriminated union features.
Example 5: Deconstructing anonymous DUs (copied from https://github.com/microsoft/qsharp-language/issues/51).
Note that this does not represent reifying arbitrary runtime type information as excluded above. Rather, the type
(Double[] | Complex[] | ComplexPolar[])
represents an anonymous DU with case constructorsDouble[]
,Complex[]
, andComplexPolar[]
, such that all possible cases are known exactly at compile time.Affidavit (please fill out)
Please add ticks by placing a cross in the box:
Please tick all that apply: