Первая проблема заключается в том, что модули абстрактного набора различаются : результат двух приложений функторов в OCaml равен только в том случае, если приложения функторов применяются к точно таким же именованным модулям. , Например, в
module A = struct type t = int end
module F(X:sig type t end) = struct type t end
module FA = F(A)
module B = A
module FA' = F(B)
module C = F(struct type t end)
типы FA.t
и Fa'.t
одинаковы
let f (x:FA.t): FA'.t = x
Но типы C.t
и FA.t
различны:
let f (x:C.t): FA'.t = x
Error: This expression has type C.t but an expression was expected of type
FA'.t
Но эту часть можно исправить, не используя анонимную структуру, когда они не нужны:
module Graph (UA : UTYPE) : (GRAPH with module U=UA) = struct
module U=UA
module AbstractUSet = Set.Make(U)
let f g uset = g uset
end
Затем у вас остается «проблема», которую определяют Game(M).AbstractUSet
и Graph(M).AbstractUSet
два разных типа. (Обратите внимание, что это, вероятно, правильное поведение вне тестов). Для теста один из вариантов - просто предоставить информацию о том, что эти модули являются результатом функторных приложений. Например, можно переопределить тип модуля GAME
(и функтор GameInstance
) следующим образом:
module type GAME = sig
type set
module P : GAME_PIECE
module AbstractVSet: Set.S with type t = set
val g : AbstractVSet.t -> AbstractVSet.t
end
module GameInstance (NA : GAME_PIECE) :
(GAME with type set:= Set.Make(NA).t and module P=NA) = struct
module P = NA
module AbstractVSet = Set.Make(NA)
let g vset = vset
end
Здесь мы получаем информацию о том, что GameInstance(M).AbstractVSet.t
того же типа, что и Set.Make(M).t
.
В сочетании с одной и той же операцией над частью графика:
module type GRAPH = sig
type set
module U : UTYPE
module AbstractUSet : Set.S with type t = set
val f : (AbstractUSet.t -> AbstractUSet.t) -> AbstractUSet.t -> AbstractUSet.t
end
module Graph (UA : UTYPE) :
(GRAPH with type set := Set.Make(UA).t and module U=UA) = struct
module U=UA
module AbstractUSet = Set.Make(UA)
let f g uset = g uset
end
мы сохраняем достаточно информации о типе, чтобы сохранить равенство для теста:
module TestGame = GameInstance(String)
module TestGraph = Graph(String)
module Test = struct
module MyGame = TestGame
module MyGraph = TestGraph
let result vset = MyGraph.f (MyGame.g) vset (* does typecheck *)
end