How to define and use % as a prefix operator?
f#
Solution
The reason why you are seeing this behavior is because F# does not define `(~%)` with static constraints like most top-level operators. It is defined as a function `Quotations.Expr<'a> -> 'a`. Hence, the `(~%)` function (which is an alias for `op_Splice`) you defined on type `T` is not resolved by uses of the top-level `(~%)` operator.
You can see this by the following FSI interaction:
> <@ (~%) @>;;
<@ (~%) @>;;
^^^^^^^^^^
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.
Thus if we redefine the top-level `(~%)` operator as follows, then your example will compile without error:
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
but do note that quotation splicing will no longer work:
let x = <@ 3 @>
<@ %x @>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
that's because the original definition of `(~%)` is treated specially by the compiler for quotation splicing. Indeed, you can see in the `Expr` and `Expr<'T>` signatures that those types do not define any operators at all, let alone `op_Splice`.
You can see similar results with `&&` and `||` infix operators. Which can be redefined (mapping to `op_BooleanAnd` and `op_BooleanOr`), but unless they are, they are treated specially by the compiler.
Problem
``` type T() = static member (~%)(t : T) = t let t = T() let t' = %t // FAILS ``` The error message says `t` was expected to be of type `Quotation.Expr<'a>`. % is a supposedly valid prefix operator, but is it possible to actually use it?