Description
Allow arbitrary expressions as active pattern arguments
I propose we allow:
- Property access
Already allowed:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
let l = "123".Length
match 3 with
| Eq l -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
match 3 with
| Eq "123".Length -> printfn "A"
(*
error FS0010: Unexpected symbol '.' in pattern matching. Expected '->' or other token.
error FS0010: Unexpected symbol '.' in pattern matching. Expected '->' or other token.
error FS0001: This expression was expected to have type
'int'
but here has type
'string'
*)
| _ -> printfn "B"
typeof
(Allow explicit type signatures for active pattern parameters #758)
Already allowed:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
let t = typeof<int>
match typeof<int> with
| Eq t -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
match typeof<int> with
| Eq typeof<int> -> printfn "A" // error FS0010: Unexpected type application in pattern matching. Expected '->' or other token.
// error FS0010: Unexpected type application in pattern matching. Expected '->' or other token.
// error FS0685: The generic function 'typeof' must be given explicit type argument(s)
| _ -> printfn "B"
- Lambdas (
fun
andfunction
)
Currently allowed:
let (|Member|) f x = f x
let f (x:System.Type) = x.BaseType
match typeof<int> with
| Member f (Member f null) -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|Member|) f x = f x
match typeof<int> with
| Member (fun x -> x.BaseType) (Member (fun x -> x.BaseType) null) -> printfn "A"
(*
error FS0010: Unexpected keyword 'fun' in pattern. Expected ')' or other token.
error FS0583: Unmatched '('
error FS0010: Unexpected symbol ')' in implementation file
error FS0010: Unexpected keyword 'fun' in pattern. Expected ')' or other token.
error FS0583: Unmatched '('
error FS0010: Unexpected symbol ')' in implementation file
error FS0001: Type mismatch. Expecting a
'System.Type -> 'a'
but given a
'('b -> 'c) -> 'b -> 'c'
The type 'System.Type' does not match the type ''a -> 'b'
*)
| _ -> printfn "B"
(Imagine this with #506 😉)
let (|Member|) f x = f x
match typeof<int> with
| Member _.BaseType (Member _.BaseType null) -> printfn "A"
| _ -> printfn "B"
(Partially applied operators are already ok too!)
let (|Apply|) f x = f x
match 1 with
| Apply ((+) 1) (Apply ((+) 1) 3) -> printfn "A"
| _ -> printfn "B"
- Computation expressions
Currently allowed:
let (|SeqEqual|_|) a = Seq.map2 (=) a >> Seq.fold (&&) true >> function true -> Some SeqEqual | false -> None
let otherSeq = seq { 1; 2; 3 }
match seq { 1; 2; 3 } with
| SeqEqual otherSeq -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|SeqEqual|_|) a = Seq.map2 (=) a >> Seq.fold (&&) true >> function true -> Some SeqEqual | false -> None
match seq { 1; 2; 3 } with
| SeqEqual (seq { 1; 2; 3 }) -> printfn "A"
(*
error FS0010: Unexpected integer literal in pattern. Expected identifier, 'global' or other token.
error FS0583: Unmatched '('
error FS0010: Unexpected integer literal in pattern. Expected identifier, 'global' or other token.
error FS0583: Unmatched '('
error FS0723: Invalid argument to parameterized pattern label
*)
| _ -> printfn "B"
- Records
Already allowed:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
type X = { x : int }
let x = { x = 3 }
match { x = 3 } with
| Eq x -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
type X = { x : int }
match { x = 3 } with
| Eq { x = 3 } -> printfn "A"
// error FS0723: Invalid argument to parameterized pattern label
| _ -> printfn "B"
- Anonymous records
Already allowed:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
let x = {| x = 3 |}
match {| x = 3 |} with
| Eq x -> printfn "A"
| _ -> printfn "B"
Should allow:
let (|Eq|_|) x = (=) x >> function true -> Some Eq | false -> None
match {| x = 3 |} with
| Eq {| x = 3 |} -> printfn "A"
// error FS0010: Unexpected symbol '{|' in pattern
// error FS0010: Unexpected symbol '{|' in pattern
| _ -> printfn "B"
The existing way of approaching this problem in F# is to annoyingly put the argument in a let
binding elsewhere!
Pros and Cons
The advantages of making this adjustment to F# are
- Consistency with the rest of F#
- Convenience when using active patterns
- Concise matching with active patterns
The disadvantages of making this adjustment to F# are (none).
Extra information
Estimated cost (XS, S, M, L, XL, XXL): S
Related suggestions: (put links to related suggestions here)
#758 - This while only being scoped to typeof
.
Affidavit (please submit!)
Please tick this by placing a cross in the box:
- This is not a question (e.g. like one you might ask on stackoverflow) and I have searched stackoverflow for discussions of this issue
- I have searched both open and closed suggestions on this site and believe this is not a duplicate
- 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:
- This is not a breaking change to the F# language design
- 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 👍 emoji on this issue. These counts are used to generally order the suggestions by engagement.