Основная проблема заключается в том, что ограничения вашей подписи делают полученный модуль слишком непрозрачным. Когда вы ограничиваете свой функтор, результат:
module FromToString (S:ToString) : Printable = ...
вы делаете тип t
абстрактным типом, который может использоваться только функцией to_string
и никогда не создается. Другими словами, модуль типа Printable
сам по себе непригоден.
При запуске с функтором очень часто полезно посмотреть на тип модуля, выведенный компилятором для результирующего модуля.
В случае FromToString
это:
module FromToString (S:ToString) : sig
type t = S.t
val print: t -> unit
end = ...
Вы можете видеть, что предполагаемый тип модуля результата
sig
type t = S.t
val print: t -> unit
end
что он очень похож на Printable
за исключением того, что теперь тип t
равен типу t
модуля аргумента S
.
Таким образом, можно повторно использовать Printable
для записи полного типа модуля результата, добавив равенство типов с ограничением with
:
module FromToString (S:ToString): Printable with type t = S.t = struct
type t = S.t
let print a = print_string ( S.to_string a)
end
Та же проблема возникает для IntToString и может быть исправлена аналогичным образом:
module IntToString : ToString with type t = int =
struct
type t = int
let to_string = string_of_int
end
Тогда ошибка компилятора исчезла:
module PrintableInt = FromToString(IntToString)
let () = PrintableInt.print 3