F# 使用typeof<_&燃气轮机;处于活动模式

F# 使用typeof<_&燃气轮机;处于活动模式,f#,active-pattern,F#,Active Pattern,鉴于以下人为活动模式: let (|TypeDef|_|) (typeDef:Type) (value:obj) = if obj.ReferenceEquals(value, null) then None else let typ = value.GetType() if typ.IsGenericType && typ.GetGenericTypeDefinition() = typeDef then Some(typ.GetGenericArgum

鉴于以下人为活动模式:

let (|TypeDef|_|) (typeDef:Type) (value:obj) =
  if obj.ReferenceEquals(value, null) then None
  else
    let typ = value.GetType()
    if typ.IsGenericType && typ.GetGenericTypeDefinition() = typeDef then Some(typ.GetGenericArguments())
    else None
以下是:

let dict = System.Collections.Generic.Dictionary<string,obj>()
match dict with
| TypeDef typedefof<Dictionary<_,_>> typeArgs -> printfn "%A" typeArgs
| _ -> ()
let dict=System.Collections.Generic.Dictionary()
匹配dict
|TypeDef typedefof typeArgs->printfn“%A”typeArgs
| _ -> ()
给出了错误:

模式匹配中出现意外的类型应用程序。应为'->'或其他标记

但这是可行的:

let typ = typedefof<Dictionary<_,_>>
match dict with
| TypeDef typ typeArgs -> printfn "%A" typeArgs
| _ -> ()
let typ=typedefof
匹配dict
|TypeDef typ typeArgs->printfn“%A”typeArgs
| _ -> ()

为什么这里不允许使用
typedefof
(或
typeof
)呢?

即使您使用的是参数化的活动模式(参数是某个表达式),编译器也会将参数解析为模式(与表达式相反),因此语法更受限制

我认为这与这里讨论的问题本质上是相同的:(我不确定实际的编译器实现,但是F#规范说它应该作为模式进行解析)

作为一种解决方法,您可以在引号内编写任何表达式,因此可以执行以下操作:

let undef<'T> : 'T = Unchecked.defaultof<_>

let (|TypeDef|) (typeExpr:Expr) (value:obj) =
  let typeDef = typeExpr.Type.GetGenericTypeDefinition()
  // ...

let dict = System.Collections.Generic.Dictionary<string,obj>()
match dict with
| TypeDef <@ undef<Dictionary<_,_>> @> typeArgs -> printfn "%A" typeArgs
| _ -> ()
让undef打印fn“%A”类型参数
| _ -> ()

除了Tomas的答案之外,本例中麻烦的语法似乎与显式类型参数有关。另一种解决方法是使用伪参数来传输类型信息

let (|TypeDef|_|) (_:'a) (value:obj) =
  let typeDef = typedefof<'a>
  if obj.ReferenceEquals(value, null) then None
  else
    let typ = value.GetType()
    if typ.IsGenericType && typ.GetGenericTypeDefinition() = typeDef then Some(typ.GetGenericArguments())
    else None

let z = 
    let dict = System.Collections.Generic.Dictionary<string,obj>()
    match dict with
    | TypeDef (null:Dictionary<_,_>) typeArgs -> printfn "%A" typeArgs
    | _ -> ()
let(| TypeDef | | |)(|:'a)(值:obj)=

让typeDef=typedefofm可能只是解析器中的一个bug;在
>
之间加一个空格有帮助吗?为了清楚并避免“这个规则永远不会匹配”的混淆,
TypeDef
应该是部分活动模式吗?i、 e.
(| TypeDef | | | | | |)而不是
(| TypeDef |)
,既然活动模式的全部功能似乎是它们与函数的虚拟互换性,你知道为什么会存在这种限制吗?我不明白为什么这里的表达式有效,而不是函数调用。是因为表达式是常量吗?我不确定C#中的
typeof
是如何实现的,但它似乎不像F#中那样是一个函数。我猜如果F#的
typeof
的实现方式类似,这可能会起作用,因为它的行为更像一个常量。@Daniel-我认为这只是一个语法限制。Stephen发布的代码可以解析为模式:
TypeDef(null:Dictionary)typeArgs
(类型规范是类型注释)。使用泛型类型参数(如
typedefof
)调用函数不能被解析为模式。这就是我所想的,这使得它看起来更简单。谢谢。很好的解决方法。我想更好地理解这些限制和通用解决方法。例如,如果您想将函数调用的结果作为参数传递给活动模式,该怎么办?不客气。事实上,我正在研究制作一个函数,它可以接受一个函数,比如
f int->int
,但是我发现要么你不能,要么我不知道如何通过类型注释来指示函数有显式的类型参数……你想用一个活动模式来做吗?或者仅仅是一个函数?我不认为有一种方法可以在不暴露类型参数的情况下实现它,无论是在返回值中还是通过参数。但是,您可以使用DU绑定这样的类型参数,以便传递给其他函数。看看这个: