module <name> =
struct
..
end;;
module type <name> =
struct (* should have been sig *)
..
end;;
ответ
Первый объявляет модуль, а второй объявляет тип модуля (он же подпись). Тип модуля содержит объявления type
и val
, тогда как модуль может содержать определения (например, привязки let
). Вы можете использовать подпись, чтобы ограничить тип модуля, как можно больше для функции. Например,
module type T = sig
val f : int -> int
end
module M : T = struct
let f x = x + 1
let g x = 2 * x
end
Теперь мы имеем
# M.f 0 ;;
- : int = 1
# M.g 0 ;;
Error: Unbound value M.g
M.g
является несвязанным, потому что она скрыта подписью T
.
Другим распространенным способом использования типов модулей является аргументация и возврат значений функторов. Например, Map.Make
функтора в the standard library принимает модуль с подписью Map.OrderedType
и создает модуль с подписью Map.S
P.S. Обратите внимание, что в вопросе есть ошибка. Тип модуля объявляются с использованием
module type <name> = sig
...
end
тип модуля описывает модуль. Это то же самое, что разница между .ml и .mli
структура (написано struct … end
) представляет собой пучок определений. Любой объект на языке может быть определен в модуле: значения ядра (let x = 2 + 2
), типы (type t = int
), модули (module Empty = struct end
), подписи (module type EMPTY = sig end
) и т. Д. Модули являются обобщением структур: структура представляет собой модуль, и поэтому является functor (подумайте об этом как о функции, которая принимает модуль как аргумент и возвращает новый модуль). Модули похожи на основные значения, но живут на одном уровне выше: модуль может содержать что угодно, тогда как базовое значение может содержать только другие значения ядра¹.
подпись (написано) является связкой спецификаций (некоторые языки используют термин декларацию). Любой объект на языке может быть указан в модуле: значения ядра (val x : int
), типы (type t = int
), модули (module Empty : sig end
), подписи (module type EMPTY = sig end
) и т. Д. Типы модулей обобщают сигнатуры: тип модуля определяет модуль и тип модуля, который определяет структуру, называется сигнатурой. Типы модулей - это модули, для которых обычные типы относятся к основным значениям.
Единицы компиляции (.ml
файлов) являются структурами. Интерфейсы (.mli
файлов) являются подписями.
Таким образом, module Foo = struct … end
определяет модуль под названием Foo
, который является структурой. Это аналогично let foo = (1, "a")
, который определяет значение, называемое foo
, которое является парой. И module type FOO = sig … end
(примечание: sig
, а не struct
) определяет тип модуля, называемый FOO
, который является сигнатурой.Это аналогично type foo = int * string
, который определяет тип, называемый foo
, который является типом продукта.
¹ Это уже не так, поскольку OCaml 3.12 представил первоклассные модули, но это достаточно близко для вводного представления.
Вы пытались скомпилировать свой тип модуля Name = struct ... end' перед тем, как задать вопрос? –
Я просто хотел проиллюстрировать пример. Я работал над большим модулем и понял, что я не хочу отвлекать людей от актуального вопроса. –