Обычно программа OCaml может быть записана с объектами или без них. Когда наиболее выгодно использовать объекты, и когда их следует избегать?
Когда в OCaml должны использоваться объекты?
Ответ 1
Как правило, не используйте объекты. Дополнительная сложность, которую они приносят, не так часто стоит того. Я думаю, что правило, применимое и к другим языкам, но это другая история. По крайней мере, с OCaml можно объективно (без каламбуры) сказать, что обычной практикой является не использование объекта, за исключением редких случаев.
Объект предоставляет пакет:
- "Стандартный" стиль для переноса и использования записей функций с возможными полиморфными типами
- Возможности для открытой рекурсии через
self
(наследование реализации) - Структурный, расширяемый тип продукта с полиморфизмом строк (для типов открытых объектов) и подтипированием (для типов закрытых объектов)
Вы можете использовать любой из них вместе или отдельно.
По моему опыту, только один пункт (1) особо не стоит использовать объекты: вы можете просто использовать записи функций, и это так же ясно.
Использует случаи открытого рекурсивного/наследования
Точка (2), наоборот, является хорошим оправданием для использования объектно-ориентированного стиля; он используется таким образом Camlp4, например: Camlp4 определяет классы, которые складываются поверх AST, ничего не делая, и вы можете наследовать этот объект обхода, чтобы реализовать поведение, которое вы хотите, только на синтаксических конструкциях, которые вы хотите (и отложить прохождение расточного обхода до ваш материнский класс).
Например, можно расширить объект Camlp4Ast.map, который определяет простую функцию карты в представлении Camlp4 абстрактных синтаксических деревьев OCaml, просто преобразуя каждую конструкцию в себя, рекурсивно. Если вы хотите, скажем, отобразить все выражения (fun x -> e1) e2
в let x = e2 in e1
, вы наследуете от этого объекта и переопределяете метод expr
, обрабатывая только тот случай, который вы хотите (левая сторона - это функция), делегирование а другой - унаследованному поведению. Это даст вам объект, который знает, как применить это преобразование по полной программе, рекурсивно, без необходимости писать какой-либо шаблонный код; и вы можете продолжить это преобразование с дополнительным поведением, если хотите.
Развлечения с типами объектов
Точка (3) также является оправданием для использования объектов как "расширяемых записей" или "массивов уровня"; некоторые библиотеки используют типы объектов, но не объекты во время выполнения: они используют типы объектов в качестве типов phantom для переноса информации, получая преимущества от более богатых операций на уровне типа, которые вы можете иметь на объектах. Кроме того, структурная типизация позволяет различным авторам иметь совместимые типы без сильных зависимостей с общей составляющей, определяющей (номинальные) типы, которыми они делятся; объекты были использованы для стандартизации компонентов ввода/вывода, например.
Необычный, очень простой пример использования - это идиоматический способ представления типов, которые имеют множество параметров. Вместо написания:
type ('name, 'addr, 'job, 'id) person = ....
val me : (string, string, Job.t, Big_int.big_int) person
вы можете использовать типы объектов как структурные "записи на уровне типа" для записи:
type 'a person = .... constraint 'a = < name:'n; addr:'a; job:'j; id:'i >
val me : < name:string; addr:string; job:Job.t; id:Big_int.big_int > person
Для более продвинутого использования типов объектов в качестве типов phantom вы можете посмотреть ShCaml (doc) (где он используется для представления того, с какими командами оболочки связан ввод строки) Алеком Хеллером и Джесси Товом или моим собственным Macaque (doc и api doc), который использует типы объектов для представления значений SQL (включая информацию о недействительности) и типов строк таблицы.
Полиморфные варианты (другая расширенная особенность системы типа OCaml, в предложении связь между объектами и записями такая же, как и связь между полиморфными вариантами и типами алгебраических сумм). Также использовались как типы phantom, например в этом простом примере Ричардом Джонсом или проверить правильность HTML-документов в Ocsigen.
Остерегайтесь, однако, что эти хакеры с расширенными типами имеют значительную сложность; перед их использованием вы должны тщательно сбалансировать его с дополнительной выразительностью и статической безопасностью, которые они приносят.
Подведение итогов
-
как базовое предположение, вы можете не использовать объекты вообще; вы должны представить их только в своем дизайне, если вы чувствуете, что чего-то не хватает, а не по умолчанию.
-
объекты удобны для открытой рекурсии/наследования: уточнение поведения, которое уже определено в стандартном/скучном случае
-
Структурная типизация иногда полезна, когда вы хотите рассуждать о значениях, независимо предоставляя набор функций/возможностей