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