9

F# 有类型化和非类型化的代码引用,我想知道在哪些用例中可以选择一个而不是另一个?

区别只是方便,无类型和类型的引用在所有情况下都可以转换为每个,或者是类型的引用,例如无类型引用可能的子集?

是否有任何示例仅适用于类型化的引用,但不适用于非类型化的引用 - 或相反?

4

2 回答 2

7

一般来说,我建议尽可能使用输入引号。像往常一样,这些类型将允许您静态地强制执行一些可能导致运行时失败的正确性条件。考虑:

let one = <@@ "one" @@>
// exception at runtime
let two = <@@ 1 + %%one @@>

let one = <@ "one" @>
// compile time error: the type 'string' does not match the type 'int'
let two = <@ 1 + %one @>

此外,有时在类型引用不需要的情况下,非类型引用需要额外的类型注释:

// ok
let l = <@ [1] @>
let l2 = <@ List.map id %l @>

// fails at runtime (obj list assumed instead of int list)
let l = <@@ [1] @@>
let l2 = <@@ List.map id %%l @@>

// ok
let l = <@@ [1] @@>
let l2 = <@@ List.map (id:int->int) %%l @@>

但是,如果您正在使用引号构建一些非常通用的东西,则可能无法使用类型化的引号(例如,因为类型不是静态已知的)。从这个意义上说,未键入的引用为您提供了更大的灵活性。

另请注意,根据需要在类型化和非类型化引号之间转换非常容易(向上Expr<_>转换 toExpr以从类型化到非类型化;使用Expr.Castto 去另一种方式)。

于 2012-05-17T18:22:54.760 回答
3

通常,报价处理库的使用者将使用键入的报价。而报价处理作者需要处理未输入的报价。

也就是说,您通常不会使用(<@@ @@>)运算符直接创建无类型引用。但是,为了使用各种 F# 核心库活动模式(例如Quotations.Patterns模块)递归处理引用,您可以使用非类型化形式的引用。

请注意,Expr<'T>扩展Expr并没有真正添加太多信息。也就是说,键入的引用实际上只是一种错觉,所有捕获的元数据都在Expr对象中并且仅在运行时可用。

于 2012-05-17T18:26:27.287 回答