ООП в Окамле

топ 100 блогов thedeemon28.06.2010 Сегодня впервые столкнулся с ситуацией, где использование ООП фич Окамла показалось уместным. Понадобилось по-разному трансформировать дерево программы в моем конпеляторе Leo. Например, нужно заменить переменные с заданными именами на заданные выражения. Или заменить везде один оператор на другой. В обоих случаях нужно аккуратно рекурсивно обойти все дерево и построить точно такое же, но в одном аспекте отличающееся. Дерево описывается набором ссылающихся друг на друга алгебраических типов - стейтменты, выражения, условия и т.д. Был бы это один тип, можно было бы следать универсальную функцию map, рекурсивно применяющую функцию-аргумент к узлам дерева, а так получается, что функций и аргументов понадобится много. Поэтому сделал иначе: объединил функции рекурсивного обхода в один класс, у которого можно переопределить нужные куски, остальное отдав на откуп унаследованной функциональности.

class mapper =  
  object(self) 
    method map_code code = List.map self#map_stmt code 
     
    method map_stmt = function 
      | Break | DefVar _ as x -> x 
      | Assign(lv, rv) -> Assign(self#map_lvalue lv, self#map_rvalue rv)    
      | Call(name, rvs) -> Call(name, List.map self#map_rvalue rvs)         
      | Comp code -> Comp(self#map_code code) 
      ... 
       
    method map_lvalue = function  ... 
    method map_rvalue = function  ... 
    method map_cond = function  ...  
  end 

Например, замена переменных по переданному набору имя-значение выглядит так:

let subst_vars smap code = 
  let o = object 
      inherit mapper as super 
      method map_lvalue = function 
        | Var name as x -> (try M.find name smap with Not_found -> x) 
        | something_else -> super#map_lvalue something_else 
    end  
  in o#map_code code

Тут создается объект неназванного типа, унаследованного от класса mapper, в нем переопределен один метод, а в нем фактически переопределен только один вариант АТД, все остальное делает базовый класс, рекурсивно проходя по всем закоулкам и вариантам дерева. Это можно еще упростить. Например, для трансформации стейтментов была добавлена такая функция:

let subst_code_by_stmt f code =  
  let o = object 
      inherit mapper as super 
      method map_stmt st =  
        match f st with Some st' -> st' | None -> super#map_stmt st 
    end  
  in o#map_code code

Использование которой для совершения конкретной трансформации сводится вообще к одной строчке:

C.subst_code_by_stmt (function C.Print x -> Some(C.Prchar x) | _ -> None) code


Кажется, без ООП так просто не получилось бы.

Оставить комментарий

Архив записей в блогах:
Полный отчет о сегодняшнем визите Януковича в Енакиево с фотографиями и интервью скорее всего будет уже завтра, а пока для затравки выкладываю один ролик. После предыдущего визита на родину президента я уже уверен - если просто взять камеру и ...
Дорогие мамы! Имею вопрос к тем, кто успешно носил слингокуртки прошлой холоднючей зимой. У меня - Ямама, купленная с рук. Недовольна я ей страшно - фасоном, тем, какое положение ребенок под курткой должен занимать, чтобы его было удобно носить, ...
Буквально на днях дирекция ЖЖ обратилась ко мне с вопросом, согласен ли я на рекламу в своем блоге. Ответил им, что выступаю против войны России в Украине, что Путин казел и что пошли они нах (свою орфографию оставляю как есть). Они три дня думали, потом переспросили: так вы согласны ...
Всем привет! 1-го января 2021 года выбрался поснимать новогодний Воронеж с высоты Azimut Hotel Voronezh . 2. Воронеж красиво украсили к новому 2021 году, подсветили фасады домов, украсили улицы праздничной иллюминацией. На фото здание Администрации города Воронежа в новогоднем ...
За последние 20 лет фотографии и новости из Ирана были довольно последовательны. Они создавали гнетущее впечатление.  Если речь шла о женщинах, то они обязательно были в бурках, еще мы видели публичные демонстрации с горящими флагами, казни. Тем не менее, в этом 80 миллионом ...