2012-05-06 10 views

Respuesta

5

La razón por la que usted está viendo este comportamiento se debe a que F # no define (~%) con restricciones estáticas como la mayoría de los operadores de primer nivel. Se define como una función Quotations.Expr<'a> -> 'a. Por lo tanto, la función (~%) (que es un alias para op_Splice) que definió en el tipo T no se resuelve con los usos del operador de nivel superior (~%).

Esto se puede ver por la siguiente interacción 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. 

Así, si volvemos a definir el nivel superior (~%) operador de la siguiente manera, a continuación, su ejemplo se compilará sin error:

let inline (~%) (x : ^a) = (^a : (static member op_Splice : ^a -> 'b) (x)) 

pero tenga en cuenta que el empalme de cotización ya no funcionará:

let x = <@ 3 @> 
<@ %x @> 
----^ 
error FS0001: The type 'Expr<int>' does not support the operator '~%' 

es porque la definición original de (~%) es tratada especialmente por el compilador para el empalme de comillas. De hecho, puede see en las firmas Expr y Expr<'T> que esos tipos no definen ningún operador en absoluto, y mucho menos op_Splice.

Puede ver resultados similares con && y || operadores de infijo. Que se puede redefinir (mapeando a op_BooleanAnd y op_BooleanOr), pero a menos que lo estén, son tratados especialmente por el compilador.

4

No estoy exactamente seguro de por qué el operador % se comporta de esta manera, pero se puede redefinir el uso mundial let vinculante:

let (~%) a = -a 
%10 

Si el operador no puede ser definida como static miembro (no estoy seguro si ese es el caso, o si me falta algo), aún puede definir una definición inline que invoca a algún miembro estático de un objeto. Esto debe darle esencialmente la misma funcionalidad:

// 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 

Antecedentes: En F # código de cotización, que se utiliza para el "empalme" de expresiones en otra expresión (para construir una expresión que se compone de otro, se han definido previamente expresión). El mensaje de error sugiere que el compilador no vio su definición.

let two = <@ 2 @> 
let oneAndTwo = <@ 1 + %two @> 
Cuestiones relacionadas