ООП в Окамле

топ 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. Запретили ЛГБТ. Даже не верится. Но приятно. Как теперь наша школа будет проводить день толерантности под радужными флагами?! 2. Сдала анализы на гормоны. Такой феерии давно не было, вышли из нормы абсолютно все гормоны. То есть если раньше только щитовидка сбоила, то теперь весь ...
Оригинал взят у putnik1 в О КНЯЗЕ И ПОЛНОЙ МРАЗИ Вынужден вернуться к теме . Есть основания. И серьезные. Немного хронологии: - вчера, 2 сентября , в 21 час 02 минуты по Мск некто Александр Черкасов , председатель совета правозащитного ...
Ангелы – это небесные  существа, которые живут вокруг нас и укрывают от бед и печалей своими белыми крыльями, однако, мало кто знает о том, что они существуют не только в небе, но и среди людей, которые прячут за своими спинами свои крылышки. ...