OCaml: рекурсия с первоклассными модулями и экзистенциальным типом

Я пытаюсь сделать функцию, которая использует два модуля (одного типа) поочередно, углубляясь в рекурсию. Я передаю модули в качестве аргументов, и все пошло не так, когда я добавил экзистенциальный тип в модуль. Что меня немного удивило, так это то, что если я сделаю функцию нерекурсивной (как и во всех удаленно похожих примерах), она работает.

Вот то, что я думаю, является минимальным примером (только один переданный модуль):

module type TEST =
  sig
    type t
    val foo : t -> unit
  end

let rec foo
          (type a)
          (module Test : TEST with type t = a)
          (arg : a) : unit =
   (* Test.foo arg *) (* <- works *)
   (* I tried various type annotations, but none worked: *)
   foo (module Test : TEST with type t = a) (arg : a)

Сообщение об ошибке для примера:

Error: This expression has type
         (module TEST with type t = a) -> a -> 'b
       but an expression was expected of type 
         (module TEST with type t = a) -> a -> 'b
       The type constructor a would escape its scope

Почему это не работает и что я могу сделать, чтобы заставить это работать?

1 ответ

Решение

Не обязательно полностью понять вашу ошибку, но при выполнении рекурсии часто лучше поместить аннотацию типа на самом высоком уровне. Вот версия, которая работает:

module type TEST =
sig
  type t
  val foo : t -> unit
end

let rec foo : type a. (module TEST with type t = a) -> a -> unit
  = fun (module Test) arg ->
    if true
      then foo (module Test) arg 
      else Test.foo arg
Другие вопросы по тегам