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