我正在阅读 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)>.
,但我不知道在哪里插入let
without genlet
; 任何提示将不胜感激。