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
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 a float[]
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 a float[]
.