Я экспериментирую с модульным языком OCaml (3.12.1), определяя функторы и сигнатуры для модулей и так далее, в основном следуя примерам из главы 2 руководства по OCaml, и я случайно наткнулся на ситуацию, когда, по-видимому, моя ментальная модель того, как функторы а сигнатуры модулей работают некорректно. Я попытался сузить ситуацию, с которой я столкнулся, до минимально возможного количества кода, поэтому не спрашивайте, чего я пытаюсь добиться, это полностью надуманный пример для демонстрации рассматриваемой функции OCaml.
Итак, у нас есть функтор, который просто предоставляет функцию тождества 'f' и параметризуется модулем, предоставляющим тип входного параметра этой функции. Полностью надуманный пример, как я уже сказал.
module type SOMETYPE = sig type t end ;;
module Identity = functor (Type: SOMETYPE) -> struct let f (x: Type.t) = x end ;;
Учитывая вышеизложенное, мы переходим к определению модуля для предоставления типа int:
module IntType = struct type t = int end ;;
.. а затем используем функтор для генерации модуля для функции идентификации int:
module IdentityInt = Identity(IntType) ;;
Конечно же, сгенерированный модуль и его Функция f ведет себя так, как ожидалось:
#IdentityInt.f(3) + 10 ;;
- : int = 13
Ментальная модель функторов как функций, принимающих модули в качестве входных данных и возвращающих модули, кажется, до сих пор служила нам правильно. Функтор Identity
ожидает в качестве входного параметра модуль сигнатуры (типа модуля) SOMETYPE, и действительно модуль, который мы предоставили ( IntType
), имеет правильную сигнатуру, поэтому создается действительный выходной модуль. ( IdentityInt
), чья функция f
ведет себя так, как ожидалось.
Теперь начинается неинтуитивная часть. Что, если мы хотим явно указать, что предоставленный модуль IntType
действительно является модулем типа SOMETYPE.Как в:
module IntType : SOMETYPE = struct type t = int end ;;
, а затем сгенерируйте выходной модуль функтора так же, как и раньше:
module IdentityInt = Identity(IntType) ;;
... давайте попробуем использовать функцию f
только что сгенерированного модуля:
IdentityInt.f 0 ;;
После чего REPL жалуется на:
"Error: This expression [the value 0] has type int but an expression was expected of type IntType.t."
Как предоставление избыточной, но правильной информации о типе может нарушить код? Даже в случае A модуль функтора Identity должен был обрабатывать модуль IntType
как тип SOMETYPE
. Так почему же явное объявление IntType
типом SOMETYPE
дает другой результат?