2
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)

4

2 回答 2

3

无论出于何种原因,像这样的模式只是简单地被禁止。只有只有一个结果的模式才能接受附加参数。

这是合法的:

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 = ...

如果我不得不推测,我会说这与可预测的运行时性能有关。当模式匹配或不匹配时,编译器可以为每个参数值只运行一次。但是,如果模式返回多个内容,其中一些内容出现在 match 表达式中,而另一些则没有,并且并非所有内容都具有相同的参数 - 找出使最小值的最佳方法变得非常复杂函数调用的数量。

于 2018-08-24T13:46:35.487 回答
1

为了补充 Fyodor 的答案,该规范非常明确地概述了有效的活动模式形式(至少比 MSDN 更多) - 有关详细信息,请参阅第 7.2.3 节活动模式。

五种有效的形式是:

  • 单个案例 -(|CaseName|) inp
  • 部分的 -(|CaseName|_|) inp
  • 多案例 -(|CaseName1|...|CaseNameN|) inp
  • 带参数的单例 -(|CaseName|) arg1 ... argn inp
  • 带参数的部分 -(|CaseName|_|) arg1 ... argn inp

不允许使用其他活动模式功能。

这里最相关的是,没有办法将多案例模式与附加参数结合起来。

于 2018-08-26T23:11:25.827 回答