Casting an untyped code quotation?
-
13-11-2019 - |
Pregunta
In the MiniCsvTypeProvider, I see the following line of code:
let prop = ProvidedProperty(fieldName, fieldTy, GetterCode = fun [row] -> <@@ (%%row:float[]).[i] @@>)
with GetterCode type is : Quotations.Expr list -> Quotations.Expr :
I don't really know what the lambda fun is doing....
it matches its input with a single element array, binding it to a variable named 'row' , of type Quotations.Expr from the GetterCode signature.
it creates a code quotation in return
- inside the code quotation, it uses %%row:float[] and I don't know what this means : is that a Float [] type constraint for untyped code quotations ?
Solución
Jack's answer is correct. I'll add a bit more context. (%%)
is the untyped splice operator (that is, it splices a Quotations.Expr
into another typed or untyped quotation), while (%)
is the typed splice operator (that is, it splices a Quotations.Expr<'t>
for some 't
into another typed or untyped quotation). (a : ty)
is just a type annotation, so (%%row : float[])
indicates that when row
is spliced into the quotation the result is a float[]
. Without this annotation, %%row
could be a value of any type, and the compiler would be unable to infer what we mean by the .[]
indexer (just as it can't infer the type of arr
in fun arr i -> arr.[i]
).
In case it's helpful, here are some alternative ways to express roughly the same thing as <@@ (%%row:float[]).[i] @@>
:
We can convert the untyped quotation to a typed quotation before splicing:
let typedRow = Quotations.Expr.Cast<float[]> row <@@ %typedRow.[i] @@>
Here we are using the typed splice operator
(%)
, so the compiler knows that%typedRow
is afloat[]
and that the.[]
operator is applicable.We can use a different way of indexing into the array so that F#'s type inference can determine the type of
%%row
without an annotation:<@@ Array.get %%row i : float @@>
Here, the
Array.get
method takes an'a[]
as an argument and we add a type annotation which indicates that the result is a float, so F# will infer that%%row
is afloat[]
.
Otros consejos
The :float[] is an explicit type annotation (not constraint, which is similar but different); it's saying %%row will produce a value of type float[].
Then by wrapping it in parenthesis, you can use the .[idx] syntax to get an element of the array because the F# compiler infers the type of the value within the parenthesis as float[].
Explicitly specifying a type annotation this way can be a useful way to give the F# compiler a "hint" and resolve type inference errors.