Избыточность в декларации типа OCaml (мл / мл) - PullRequest
32 голосов
/ 13 июля 2010

Я пытаюсь понять конкретную вещь о модулях ocaml и их компиляции:

я вынужден повторно объявить типы, уже объявленные в .mli внутри конкретных .ml реализаций?

Просто чтобы привести пример:

(* foo.mli *)
type foobar = Bool of bool | Float of float | Int of int

(* foo.ml *)
type baz = foobar option

Это, в соответствии с моим обычным представлением об интерфейсах / реализациях, должно быть в порядке, но оно говорит:

Ошибка: несвязанный типконструктор foobar

при попытке компиляции с

ocamlc -c foo.mli
ocamlc -c foo.ml

Конечно, ошибка исчезнет, ​​если я тоже объявлю foobar внутри foo.ml, но это кажется сложным способом, так как у меня естьчтобы все синхронизировалось при каждом изменении.

Есть ли способ избежать этой избыточности, или я вынужден каждый раз переопределять типы?

Заранее спасибо

Ответы [ 5 ]

18 голосов
/ 13 июля 2010

Да, вы вынуждены переопределить типы .Я знаю только об этом:

  • Не используйте файл .mli;просто выставить все без интерфейса.Ужасная идея.

  • Используйте инструмент грамотного программирования или другой препроцессор, чтобы избежать дублирования объявлений интерфейса в One True Source.Для больших проектов мы делаем это в моей группе.

Для небольших проектов мы просто дублируем объявления типов.И ворчать об этом.

17 голосов
/ 17 июля 2010

OCaml пытается заставить вас отделить интерфейс (.mli) от реализации (.ml. В большинстве случаев это хорошо; для значений вы публикуете тип в интерфейсе и сохраняете код в реализации. Можно сказать, что OCaml применяет определенное количество абстракций (интерфейсы должны быть опубликованы; код в интерфейсах отсутствует).

Для типов очень часто реализация совпадает с интерфейсом: оба утверждают, что тип имеет конкретное представление (и, возможно, объявление типа является генеративным). Здесь не может быть абстракции, потому что у разработчика нет никакой информации о типе, который он не хочет публиковать. (Исключение в основном при объявлении абстрактного типа.)

Один из способов взглянуть на это состоит в том, что интерфейс уже содержит достаточно информации для написания реализации. Учитывая интерфейс type foobar = Bool of bool | Float of float | Int of int, возможна только одна реализация. Так что не пишите реализацию!

Распространенная идиома - иметь модуль, который предназначен для объявлений типов, и сделать так, чтобы он имел только .mli. Поскольку типы не зависят от значений, этот модуль обычно входит очень рано в цепочку зависимостей. Большинство инструментов компиляции хорошо справляются с этим; например ocamldep будет делать правильные вещи. (Это одно преимущество по сравнению с .ml.)

Ограничением этого подхода является то, что вам также нужно несколько определений модуля здесь и там. (Типичным примером является определение типа foo, затем модуля OrderedFoo : Map.OrderedType с type t = foo, а затем еще одно объявление типа, включающее 'a Map.Make(OrderedFoo).t.) Они не могут быть помещены в файлы интерфейса. Иногда допустимо разбить ваши определения на несколько частей: сначала набор типов (types1.mli), затем модуль (mod1.mli и mod1.ml), а затем несколько типов (types2.mli). В других случаях (например, если определения являются рекурсивными) вы должны жить с .ml без .mli или дублированием.

13 голосов
/ 14 июля 2010

Вы можете позволить ocamlc сгенерировать для вас файл mli из файла ml:

ocamlc -i some.ml > some.mli
3 голосов
/ 14 июля 2010

В общем, да, вам необходимо дублировать типы.

Однако вы можете обойти это, используя Camlp4 и расширение синтаксиса pa_macro (пакет findlib: camlp4.macro). Он определяет, среди прочего, и ВКЛЮЧИТЬ конструкцию. Вы можете использовать его для выделения общих определений типов в отдельный файл и включения этого файла в файлы .ml и .mli. Однако я не видел, чтобы это было сделано в развернутом проекте OCaml, поэтому я не знаю, что это будет считаться рекомендуемой практикой, но это возможно.

Решение для грамотного программирования, однако, является более чистым ИМО.

0 голосов
/ 20 ноября 2010

Нет, в файле mli просто скажите «введите foobar». Это будет работать.

...