Я экспериментирую с языком модуля 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
дает другой результат?