ООП в Окамле

топ 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


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

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

Архив записей в блогах:
Как и обещал, сегодня выходит один из последних выпусков данной рубрики. Пусть, не совсем вовремя, но как уж получается. Обсудим прошедший пуск на МЦД-3, а также другие новости, накопившиеся за месяц. Пуск третьего Московского Центрального Диаметра ...
Куда приводят мечты... Февраль, 2010. Москва, Россия Два друга решили ограбить салон сотовой связи. План был банален до безобразия — вошли, попросили показать самые дорогие модели, а когда молоденькая продавщица достала с витрины несколько ...
И грядут достаточно давно. China Evergrande Group , Компания, созданная в 1996 году. Не в Китае, прошу заметить, а в оффшоре Каймановых островов.  И собственники там интересные. Свежих данных по акционерам, увы, не нашлось, но на 2018 год 77,5% акций (т.е. не просто контрольный ...
Нет, ну давайте чисто теоретически прикинем... У нас есть ЗОГ "ономнядцатого века". Вопрос реальности существования ЗОГа вообще в каком-либо веке задавать не будем - мы же пытаемся думать как озабоченные тупые неучи . Итак, ЗОГ направил свои козни... естественно, на святую Русь. Потому чт ...
Когда выбирала для себя новое место жительства, язык и возможность общения стояли на первом месте. Ну ладно я, человек взрослый, ко всему привыкший. Знаю испанский (считай половина мира открыта), значительно хуже, но «почти знаю» и английский (практики побольше и считай вторая половина мир ...