Вставка let для привязки локальной переменной
Я прорабатываю руководство Олега Киселева " Согласование абстракции с высокой производительностью: подход MetaOCaml". В одном упражнении (упражнение 23) требуется let-insert для привязки доступа индекса массива к локальной переменной. Функция вопроса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
без genlet
; любой намек будет оценен.
1 ответ
Let-вставка - это примитивная операция в BER, которая автоматически привязывает переданный код к только что сгенерированной переменной.
Вот рабочий пример. Предположим, у вас есть код, который возвращает квадрат элемента массива.
let power_elt xs i = xs.(i) * xs.(i)
и мы хотим сгенерировать оптимизированный код, который имеет доступ только к одному массиву
let power_elt xs i = let x = xs.(i) in x*x
В стиле MetaOCaml мы можем использовать genlet
для этого
let power_elt xs i =
let x = genlet .<xs.(i)>. in
.<.~x * .~x>.
Сгенерированный код для
let t = power_elt [|1;2;3|] 1;;
будет
val t : int code = .<let lv_8 = Stdlib.Array.get (* CSP xs *) 1 in lv_8 * lv_8>.