Вставка 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>.
Другие вопросы по тегам