Вкратце, тип ссылки должен быть определен до ее создания: вы должны иметь возможность комментировать тип print
при первом его определении.И, поменяв определения a
и print
, вы сделали эту последнюю точку невозможной:
let print: ( ??? -> unit) ref = ref (fun _ -> ())
type a = A of int
Здесь ???
должно быть a
, но тип a
еще предстоитбыть определенным.
Точнее, типы в OCaml имеют область видимости, чтобы определять, когда локальный тип выходит за пределы контекста, где он определен и имеет смысл.Например,
let x =
let module M = struct type t = A end in
M.A
завершается ошибкой с той же ошибкой, что и во втором примере
Ошибка: это выражение имеет тип Mt, но ожидалось выражение типа 'a Конструктор типа Mtэкранировать область действия
Здесь разрешить типу M.t
экранировать тело определения x
было бы плохо, поскольку модуль M
и, следовательно, тип M.t
не определены внеэтого определения.
Ваш пример терпит неудачу по той же причине.Переменная
let print = ref (fun _ -> ())
имеет тип ('_weak1 -> unit) ref
, где '_weak1
- это тип заполнителя для еще неизвестного типа.Но будущий тип ссылки уже должен существовать в этой точке.
Таким образом, когда вы определяете новый тип
type t = A of int
и пытаетесь присвоить этот тип слабому типу '_weak1
переменная,
let print': (t -> unit) ref = print
проверка типов жалуется, что тип t
был неопределен при создании переменной типа '_weak1
:
Ошибка: это выражение имеет тип ('weak1-> unit) ref, но ожидалось выражение типа (t -> unit) ref Конструктор типа t выйдет из области видимости
Аналогично, ваша функция f
let f x = !print (A x)
подразумевает, что тип !print
будет t -> unit
и приведет к аналогичной ошибке:
Ошибка: это выражение имеет тип t, но ожидалось выражение типа 'weak1 Конструктор типат выйдет за рамки