Я не эксперт, но вот мое мнение по этому поводу.
Настоящая ошибка - это последний бит сообщения:
Конструктор типа F.t выйдет за пределы своей области видимости.
Чтобы понять сообщение об ошибке, давайте сначала перепишем any_foo
без сопоставления аргумента с шаблоном и переименуем аргумент, чтобы облегчить объяснение:
let any_foo arg foo =
let (module F : Foo) = foo in
F.do_with_t arg
Здесь вы используете первоклассные модули и распаковываете переменную foo
в новый модуль F
, в рамках этого оператора let.
Теперь давайте рассмотрим тип аргумента arg
, который может быть выведен из этого факта. Ясно, что это тип F.t
, но, что критически важно, это тип, который известен только в текущей области, потому что module F
известен только в текущей области.
Теперь попробуем определить тип результирующей any_foo
функции:
val any_foo : F.t -> (module Foo) -> unit
И вот ваша проблема, вы пытаетесь раскрыть только что созданный тип F.t
из глубины области действия функции. Другими словами, вы ожидаете, что вызывающая сторона знает тип, который существует только внутри вашей функции. Или, говоря другими словами, вы ожидаете, что тип F.t
«ускользнет» из своей области и попадет в более широкую аудиторию.
Решение, объясненное
Теперь, когда мы знаем проблему, мы можем осознать необходимость объяснить компилятору, что этот тип существует во «внешней» области и что аргумент arg
относится к этому типу.
Другими словами, нам нужно добавить ограничение к нашему недавно созданному модулю F
, чтобы сказать, что тип аргумента arg
равен типу t
внутри нашего нового модуля F
. Для этого мы можем использовать локально абстрактный тип.
Продолжая использовать ту же функцию, мы можем добавить локально абстрактный тип a
и ограничить им модуль F
:
let (type a) any_foo arg foo =
let (module F : Foo with type t = a) = foo in
F.do_with_t arg
Давайте теперь рассмотрим тип any_foo
.
val any_foo : 'a -> (module Foo with type t = 'a) -> unit
Никаких проблем нет.
Для полноты картины вернемся к нашей версии сопоставления с образцом:
let (type a) any_foo arg (module F : Foo with type t = a) =
F.do_with_t arg
07.02.2014