ActivePattern 与 System.Type 匹配有什么问题?
What's wrong with ActivePattern matching against System.Type?
module Reflection =
[<RequireQualifiedAccess>]
module Type =
let isType<'a> = Unchecked.defaultof<'a>
let (|IsEqual|Isnt|) (_:'a) (t:Type):Choice<unit,unit> =
let t' = typeof<'a>
if t = t' then IsEqual else Isnt
let (|TypeOf|_|) (_:'a) (t:Type) :unit option =
if t = typeof<'a> then Some ()
else
//printfn "did not match %A to %A" typeof<'a> t
None
open Reflection
match typeof<string> with
// compiles just fine
| Type.TypeOf (Type.isType:int) as x -> Some x.Name
// does not compile
| Type.IsEqual (Type.isType:string) as x -> Some x.Name
| _ -> None
给出Type mismatch. Expecting a Type -> Choice<'a,'b> but given a Type -> 'c -> Choice<unit,unit> The type 'Choice<'a,'b>' does not match the type ''c -> Choice<unit,unit>' (using external F# compiler)
无论出于何种原因,像这样的模式都被简单地禁止了。只有只有一个结果的模式才能接受额外的参数。
这是合法的:
let (|A|) x y = if x = y then 5 else 42
let f (A "foo" a) = printfn "%A" y
f "foo" // Prints "5"
f "bar" // Prints "42"
这是合法的:
let (|B|_|) x y = if x = y then Some (y+5) else None
let f = function
| B 42 x -> printfn "%d" x
| _ -> printfn "try again"
f 42 // prints "47"
f 5 // prints "try again"
但仅此而已。所有其他活动模式必须是无参数的。这两个都是非法的:
let (|A|B|) x y = ...
let (|A|B|_|) x y = ...
如果非要我推测的话,我会说这与可预测的 运行 时间性能有关。当模式匹配或不匹配时,编译器可以 运行 它对每个参数值恰好一次。但是如果模式 returns 有多个东西,其中一些东西出现在匹配表达式中,而另一些则没有,而且并非所有东西都具有相同的参数 - 找出最佳方法变得非常复杂进行最少的函数调用。
为了补充 Fyodor 的回答,spec 在概述有效的活动模式形式时非常明确(至少比 MSDN 更明确)- 有关详细信息,请参阅段落 7.2.3 活动模式。
五种有效形式是:
- 单例 -
(|CaseName|) inp
- 部分 -
(|CaseName|_|) inp
- 多案例 -
(|CaseName1|...|CaseNameN|) inp
- 带参数的单例 -
(|CaseName|) arg1 ... argn inp
- 部分参数 -
(|CaseName|_|) arg1 ... argn inp
不允许使用其他活动模式功能。
这里最相关的是,无法将多案例模式与其他参数结合起来。
module Reflection =
[<RequireQualifiedAccess>]
module Type =
let isType<'a> = Unchecked.defaultof<'a>
let (|IsEqual|Isnt|) (_:'a) (t:Type):Choice<unit,unit> =
let t' = typeof<'a>
if t = t' then IsEqual else Isnt
let (|TypeOf|_|) (_:'a) (t:Type) :unit option =
if t = typeof<'a> then Some ()
else
//printfn "did not match %A to %A" typeof<'a> t
None
open Reflection
match typeof<string> with
// compiles just fine
| Type.TypeOf (Type.isType:int) as x -> Some x.Name
// does not compile
| Type.IsEqual (Type.isType:string) as x -> Some x.Name
| _ -> None
给出Type mismatch. Expecting a Type -> Choice<'a,'b> but given a Type -> 'c -> Choice<unit,unit> The type 'Choice<'a,'b>' does not match the type ''c -> Choice<unit,unit>' (using external F# compiler)
无论出于何种原因,像这样的模式都被简单地禁止了。只有只有一个结果的模式才能接受额外的参数。
这是合法的:
let (|A|) x y = if x = y then 5 else 42
let f (A "foo" a) = printfn "%A" y
f "foo" // Prints "5"
f "bar" // Prints "42"
这是合法的:
let (|B|_|) x y = if x = y then Some (y+5) else None
let f = function
| B 42 x -> printfn "%d" x
| _ -> printfn "try again"
f 42 // prints "47"
f 5 // prints "try again"
但仅此而已。所有其他活动模式必须是无参数的。这两个都是非法的:
let (|A|B|) x y = ...
let (|A|B|_|) x y = ...
如果非要我推测的话,我会说这与可预测的 运行 时间性能有关。当模式匹配或不匹配时,编译器可以 运行 它对每个参数值恰好一次。但是如果模式 returns 有多个东西,其中一些东西出现在匹配表达式中,而另一些则没有,而且并非所有东西都具有相同的参数 - 找出最佳方法变得非常复杂进行最少的函数调用。
为了补充 Fyodor 的回答,spec 在概述有效的活动模式形式时非常明确(至少比 MSDN 更明确)- 有关详细信息,请参阅段落 7.2.3 活动模式。
五种有效形式是:
- 单例 -
(|CaseName|) inp
- 部分 -
(|CaseName|_|) inp
- 多案例 -
(|CaseName1|...|CaseNameN|) inp
- 带参数的单例 -
(|CaseName|) arg1 ... argn inp
- 部分参数 -
(|CaseName|_|) arg1 ... argn inp
不允许使用其他活动模式功能。
这里最相关的是,无法将多案例模式与其他参数结合起来。