2017-02-19 9 views
0

Я прочитал несколько подобных вопросов и некоторые онлайн-примеры, но я до сих пор не знаю, как написать файл .mli в этом конкретном случае.Использование файлов .mli и карты

В моем проекте я использую общий модуль карты с ключами int, который затем я специализируюсь в зависимости от значений, которые я хочу сохранить. Скажем, я хочу использовать его для хранения пар, поэтому у меня есть такой файл :

file dataStr.ml:

module IntOrder = 
    struct 
     type t = int 
     let compare = Pervasives.compare 
    end 

module IntMap = Map.Make(IntOrder) 

type couple = int * int 
(* pretty names *) 
type int2couple = couple IntMap.t 
module Couples = struct type t = int2couple end 

файл, используя этот подмодуль будет:

file useMap.ml:

open DataStr 

let use k m = 
    IntMap.add k ((Random.int 6), (Random.int 8)) m 

с интерфейсом:

file useMap.mli:

open DataStr 

val use : int -> Couples.t -> Couples.t 

До сих пор, так хорошо.

Давайте теперь предположим, что хочу представить подмодуль Couples, но не тип int2couple. Я бы тогда написать этот интерфейс:

file dataStr.mli:

module IntMap : Map.S with type key = int 

module Couples : sig type t end 
(* 
I'd like to avoid the redundancy of using 
module Couples : sig type t = (int * int) IntMap.t end 
*) 

Проблема заключается в том, если я добавить этот интерфейс, я получаю эту ошибку компиляции:

Error: The implementation useMap.ml does not match the interface useMap.cmi: 
     Values do not match: 
     val use : 
      DataStr.IntMap.key -> 
      (int * int) DataStr.IntMap.t -> (int * int) DataStr.IntMap.t 
     is not included in 
     val use : int -> DataStr.Couples.t -> DataStr.Couples.t 

Есть ли способ, чтобы написать интерфейс что позволяет мне делать то, что я хочу делать, кроме «лишнего» в комментарии?

+0

Если инкапсулировать тип '(интермедиат * целое) IntMap.t' есть нет способа узнать внешний 'DataStr', который на самом деле является картой. – mookid

+0

И я догадываюсь, что этот уровень инкапсуляции не достигает многого. Что вы хотите скрыть от кода клиента? – mookid

+0

Я хотел бы просто показать «Пары», скрывая «int2couple» и, возможно, «пару», так как я создал их, чтобы использовать их 'dataStr.ml'. Нет особых причин для того, что я пытаюсь получить, кроме читаемости интерфейса. – pimple

ответ

0

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

Лучшее, что вы можете сделать, это следующее:

$ cat dataStr.mli:

module IntMap : Map.S with type key = int 
type couple = int * int 
type int2couple = couple IntMap.t 
module Couples : sig type t = int2couple end 

$ cat dataStr.ml:

module IntOrder = 
    struct 
     type t = int 
     let compare = Pervasives.compare 
    end 

module IntMap = Map.Make(IntOrder) 

type couple = int * int 
type int2couple = couple IntMap.t 
module Couples = struct type t = int2couple end