ООП в Окамле
Jun. 28th, 2010 09:36 pmСегодня впервые столкнулся с ситуацией, где использование ООП фич Окамла показалось уместным. Понадобилось по-разному трансформировать дерево программы в моем конпеляторе Leo. Например, нужно заменить переменные с заданными именами на заданные выражения. Или заменить везде один оператор на другой. В обоих случаях нужно аккуратно рекурсивно обойти все дерево и построить точно такое же, но в одном аспекте отличающееся. Дерево описывается набором ссылающихся друг на друга алгебраических типов - стейтменты, выражения, условия и т.д. Был бы это один тип, можно было бы следать универсальную функцию map, рекурсивно применяющую функцию-аргумент к узлам дерева, а так получается, что функций и аргументов понадобится много. Поэтому сделал иначе: объединил функции рекурсивного обхода в один класс, у которого можно переопределить нужные куски, остальное отдав на откуп унаследованной функциональности.
Например, замена переменных по переданному набору имя-значение выглядит так:
Тут создается объект неназванного типа, унаследованного от класса mapper, в нем переопределен один метод, а в нем фактически переопределен только один вариант АТД, все остальное делает базовый класс, рекурсивно проходя по всем закоулкам и вариантам дерева. Это можно еще упростить. Например, для трансформации стейтментов была добавлена такая функция:
Использование которой для совершения конкретной трансформации сводится вообще к одной строчке:
Кажется, без ООП так просто не получилось бы.
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
Кажется, без ООП так просто не получилось бы.
Вспомнилось подходящее к случаю.
Date: 2010-06-28 08:03 pm (UTC)Chastised, Anton took his leave from his master and returned to his cell, intent on studying closures. He carefully read the entire "Lambda: The Ultimate..." series of papers and its cousins, and implemented a small Scheme interpreter with a closure-based object system. He learned much, and looked forward to informing his master of his progress.
On his next walk with Qc Na, Anton attempted to impress his master by saying "Master, I have diligently studied the matter, and now understand that objects are truly a poor man's closures." Qc Na responded by hitting Anton with his stick, saying "When will you learn? Closures are a poor man's object." At that moment, Anton became enlightened.
Re: Вспомнилось подходящее к случаю.
Date: 2010-06-29 02:44 am (UTC)Не подскажете, как в замыканиях реализуются виртуальные методы? :)
Выше был вариант, но там и замыканий-то нет, там С-style ООП.
Re: Вспомнилось подходящее к случаю.
Date: 2010-06-29 07:08 am (UTC)К сожалению, несколько разжеванно:
MIT 6.001 Spring 2005 L16 (http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/lecture-notes/lecture16webhan.pdf)
MIT 6.001 Spring 2005 L17 (http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/lecture-notes/lecture17_webhan.pdf)
MIT 6.001 Spring 2005 L18 (http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/lecture-notes/lecture18_webhan.pdf)