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?

Original source

Related problems