Модули 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