Модули OCaml: приведение (взаимосвязанных) типов из разных модулей в новый модуль
проблема
одна проблема, с которой я сталкиваюсь, - это приведение типов и vals двух модулей в новый комбинированный модуль. Приведу пример. В настоящее время у меня есть следующие две подписи типа
module type Ordered =
sig
type t (* the type of elements which have an order *)
val eq : t * t -> bool
val lt : t * t -> bool
val leq : t * t -> bool
end
module type Stack =
sig
exception Empty
type 'a t (* the type of polymorphic stacks *)
val empty : 'a t
val isEmpty : 'a t -> bool
val cons : 'a * 'a t -> 'a t
val head : 'a t -> 'a
val tail : 'a t -> 'a t
end
и я хотел бы создать модуль "стеков, для которых упорядочены основные элементы", т. е.
module type OrderedStack =
sig
exception Empty
type elem (* the type of the elements in the stack *)
val eq : elem * elem -> bool
val lt : elem * elem -> bool
val leq : elem * elem -> bool
type t (* the type of monomorphic stacks *)
val empty : t
val isEmpty : t -> bool
val cons : elem * t -> t
val head : t -> elem
val tail : t -> t
end
до сих пор все хорошо и аккуратно. Но теперь я хотел бы написать функтор, который принимает упорядоченный модуль и модуль стека и создает модуль OrderedStack. Что-то вроде
module My_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
exception Empty
type elem = Elem.t
let eq = Elem.eq
let lt = Elem.lt
let leq = Elem.leq
type t = elem St.t
let empty = St.empty
let isEmpty = St.isEmpty
let cons = St.cons
let head = St.head
let tail = St.tail
end
это именно то, что я хочу и правильно. Но, похоже, зря клавиатуру.
у меня вопрос
есть ли более компактный способ записи My_functor
выше?
то, что я узнал, но не мог заставить работать
я видел include
директива, в которой я мог бы написать что-то вроде:
module my_functor (Elem : Ordered) (St : Stack): OrderedStack =
struct
include Elem
include St
end
но в этом есть проблема, что для моего конкретные два модуля выше, как упорядоченные, так и стековые имеют одинаковое type t
(хотя они означают разные вещи в каждой из них). Я бы предпочел не изменять исходное определение Ordered
и Stacks
поскольку они уже используются во многих частях кода, но если вы найдете альтернативную формулировку для исходных двух модулей, которая заставляет его работать, это нормально.
я также видел, что with
оператор может быть уместной здесь, но я не мог понять, как это следует использовать для получения желаемого эффекта. Проблема, с которой я сталкиваюсь, заключается в том, что типы t
и 'a t
из двух модулей Ordered
и Stacks
и на самом деле связаны.
какие идеи?
1 ответов
OrderedStack повторно использовать упорядоченные определения, с немного другим типом (elem
вместо t
). Это причина избыточности.
вы могли бы использовать этот OrderedStack
подпись непосредственно повторное использование Ordered
:
module type OrderedStack = sig
module Elem : Ordered
type t
val empty : t
val isEmpty : t -> bool
val cons : Elem.t * t -> t
val head : t -> Elem.t
val tail : t -> t
end
еще одним источником избыточности является тот факт, что вы переходите от параметрического типа,'a Stack.t
, к мономорфным OrderedStack.t
. Эти два типа не могут быть приравнены, они вообще не сопоставимы, поэтому обязательно есть перевод, чтобы сделать вручную здесь.
обратите внимание, что вы можете разложить перемещение из (полиморфного)Stack
to OrderedStack
в один промежуточный стек, (мономорфный) MonoStack
:
module type MonoStack = sig
type elem
type t
val empty : t
val isEmpty : t -> bool
val cons : elem * t -> t
val head : t -> elem
val tail : t -> t
end
module type OrderedStack = sig
module Elem : Ordered
module Stack : MonoStack with type elem = Elem.t
end
редактировать
Если вам не нравится дополнительная косвенность использования подмодулей, которая может добавить некоторую синтаксическую нагрузку, можно включить модули вместо ссылки на них. Но проблема, как вы заметили, заключается в конфликте имен. Начиная с OCaml 3.12, у нас есть новая конструкция в нашем наборе инструментов, которая позволяет переименовывать компоненты типов сигнатур, чтобы избежать конфликтов.
module type OrderedStack = sig
type elem
include Ordered with type t := elem
include MonoStack with type elem := elem
end
Вторая Правка
ладно, я придумал следующее решение, чтобы принести Stack
/MonoStack
мост. Но, честно говоря, это хак, и я не думаю, что это хорошая идея.
module type PolyOrderedStack = sig
module Elem : Ordered
type t
type 'a const = t
module Stack : Stack with type 'a t = 'a const
end
(* 3.12 only *)
module type PolyOrderedStack = sig
type elem
include Ordered with type t := elem
type t
type 'a const = t
include Stack with type 'a t := 'a const
end