我正在阅读 Oleg Kiselyov 的教程Reconciling Abstraction with High Performance: A MetaOCaml approach。一个练习(练习 23)要求使用 let-insertion 将数组索引访问绑定到局部变量。question 的函数是vmult_ca,它生成用于将复数数组相乘的代码:
let vmult_ca :
(float_complex array -> float_complex array -> float_complex array -> unit)
code =
.<fun vout v1 v2 ->
let n = Array.length vout in
(* vector representations *)
.~(let vout = OVec (.<n>., fun i v ->
.<vout.(.~i) <- .~(of_code_complex v)>.) in
let v1 = Vec (.<n>., fun i ->
of_complex_code .<v1.(.~i)>.) in
let v2 = Vec (.<n>., fun i ->
of_complex_code .<v2.(.~i)>.) in
let module V = VMULT(FloatCodeComplex)(VecDyn) in
V.vmult vout v1 v2)
>.
;;
vout存储结果的输出向量
在哪里。Vec (n, fun i -> v)是一个抽象向量,其中n是长度,并将fun i -> v每个索引映射到一个值。
OVec (n, fun i v -> body)是一个抽象的“输出向量”,其中n是长度并且fun i v -> body在每个索引i和相关输出元素v上运行i。
of_complex_code将一个complex code值转换为一个code complex值,例如.<{real=1.0, imag=0.0}>.转换为{real=.<1.0>., imag=.<0.0>.}. 该模块VMULT定义(逐点)向量乘法(有关详细信息,请参见此处的代码)。
运行时,vmult_ca生成以下代码:
val vmult_ca :
(float_complex array -> float_complex array -> float_complex array -> unit)
code = .<
fun vout_4 ->
fun v1_5 ->
fun v2_6 ->
let n_7 = Array.length vout_4 in
for i_8 = 0 to n_7 - 1 do
vout_4.(i_8) <-
{
Cmplx.im =
(((v1_5.(i_8)).Cmplx.re *. (v2_6.(i_8)).Cmplx.im) +.
((v1_5.(i_8)).Cmplx.im *. (v2_6.(i_8)).Cmplx.re));
Cmplx.re =
(((v1_5.(i_8)).Cmplx.re *. (v2_6.(i_8)).Cmplx.re) -.
((v1_5.(i_8)).Cmplx.im *. (v2_6.(i_8)).Cmplx.im))
}
done>.
注意v1_5.(i_8)重复4次。let挑战是在某处插入一个vmult_ca绑定v1_5.(i_8)到局部变量以避免重复。genlet我可以通过简单地调用来“作弊” .<v1.(~i)>.,但我不知道在哪里插入letwithout genlet; 任何提示将不胜感激。