type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
エラーメッセージはt
、タイプがであると予想されたことを示していますQuotation.Expr<'a>
。%はおそらく有効なプレフィックス演算子ですが、実際に使用することは可能ですか?
type T() =
static member (~%)(t : T) = t
let t = T()
let t' = %t // FAILS
エラーメッセージはt
、タイプがであると予想されたことを示していますQuotation.Expr<'a>
。%はおそらく有効なプレフィックス演算子ですが、実際に使用することは可能ですか?
この動作が見られる理由は、F#が(~%)
ほとんどのトップレベルの演算子のように静的な制約で定義されていないためです。関数として定義されていますQuotations.Expr<'a> -> 'a
。したがって、typeで定義した(~%)
関数(のエイリアス)は、トップレベルの演算子を使用しても解決されません。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.
したがって、トップレベルの(~%)
演算子を次のように再定義すると、例はエラーなしでコンパイルされます。
let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x))
ただし、引用符のスプライシングは機能しなくなることに注意してください。
let x = <@ 3 @>
<@ %x @>
----^
error FS0001: The type 'Expr<int>' does not support the operator '~%'
これは、の元の定義が(~%)
、引用スプライシングのためにコンパイラによって特別に処理されるためです。実際、とシグニチャを見ると、これらの型は、ましてや演算子をまったく定義していないことがわかります。Expr
Expr<'T>
op_Splice
&&
演算子と||
中置演算子で同様の結果を見ることができます。op_BooleanAnd
これは再定義(およびにマッピングop_BooleanOr
)できますが、再定義されない限り、コンパイラによって特別に処理されます。
%
演算子がこのように動作する理由は正確にはわかりませんが、グローバルlet
バインディングを使用して再定義できます。
let (~%) a = -a
%10
演算子をstatic
メンバーとして定義できない場合(それが当てはまるかどうかわからない場合、または何かが足りない場合)でもinline
、オブジェクトの静的メンバーを呼び出す定義を定義できます。これにより、基本的に同じ機能が得られます。
// Instead of defining static member '%', we define static member 'Percent'
type T() =
static member Percent(t : T) = t
// Inline definition of '~%' that calls the static member 'Percent' of an object
let inline (~%) (x : ^T) = (^T : (static member Percent : ^T -> 'R) (x))
// Now you can use the '%t' syntax to invoke the static member
let t = T()
let t' = %t
背景: F#引用コードでは、式を別の式に「スプライシング」するために使用されます(以前に定義された別の式から構成される式を作成するため)。エラーメッセージは、コンパイラが定義を認識しなかったことを示しています。
let two = <@ 2 @>
let oneAndTwo = <@ 1 + %two @>