type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
Run Code Online (Sandbox Code Playgroud)
错误消息说t
预计是类型Quotation.Expr<'a>
.%是一个所谓的有效前缀运算符,但它是否可以实际使用它?
您之所以看到这种行为,是因为F#没有(~%)
像大多数顶级运算符那样定义静态约束.它被定义为一个函数Quotations.Expr<'a> -> 'a
.因此,您在类型上定义的(~%)
函数(它是别名op_Splice
)T
不能通过使用顶级(~%)
运算符来解决.
您可以通过以下FSI交互来看到这一点:
> <@ (~%) @>;;
<@ (~%) @>;;
^^^^^^^^^^
C:\Users\Stephen\AppData\Local\Temp\stdin(5,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : Expr<(Expr<'_a> -> '_a)>
Either define 'it' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation.
Run Code Online (Sandbox Code Playgroud)
因此,如果我们(~%)
按如下方式重新定义顶级运算符,那么您的示例将编译而不会出现错误:
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
Run Code Online (Sandbox Code Playgroud)
但请注意引用拼接将不再起作用:
let x = <@ 3 @>
<@ %x @>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
Run Code Online (Sandbox Code Playgroud)
这是因为(~%)
编译器特别为原始定义处理引用拼接.事实上,你可以看到在Expr
和Expr<'T>
签名,这些类型完全不定义任何运营商,更不用说op_Splice
.
您可以使用&&
和中||
缀运算符查看类似的结果.哪个可以重新定义(映射到op_BooleanAnd
和op_BooleanOr
),但除非它们是,否则它们将由编译器专门处理.