У меня возникли проблемы с пониманием определения letrec для системы HM, которое приведено в Википедии, здесь: https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Recursive_definitions
Для меня правило грубо переводится по следующему алгоритму:
- выводить типы на все в разделе определения
letrec- присваивать переменные временного типа каждому определенному идентификатору
- рекурсивно обрабатывать все определения с временными типами
- в парах, унифицируйте результаты с исходными временными переменными
- закрыть (с
forall) выводимые типы, добавить их в базу (контекст) и вывести типы выражения с ней
У меня возникают проблемы с такой программой:
letrec
p = (+) --has type Uint -> Uint -> Uint
x = (letrec
test = p 5 5
in test)
in x
Поведение, которое я наблюдаю, выглядит следующим образом:
- определение
pполучает временный типa - определение
xтакже получает некоторый временный тип, но теперь из нашей области - in
x, определениеtestполучает временный типt -
pполучает временный типaиз области действия, используя правило HM для переменной -
(f 5)обрабатывается по правилу HM для приложения, итоговый тип -b(и унификация, которая (aобъединяется сUint -> b) -
((p 5) 5)обрабатывается по тому же правилу, что приводит к большему количеству унификаций и типуc,aтеперь в результате объединяется сUint -> Uint -> c - теперь тест закрывается, чтобы ввести
forall c.c - переменная test
in testполучает экземпляр типа (илиforall c.c) со свежими переменными, в соответствии с правилом HM для переменной, в результате чегоtest :: d(который унифицирован сtest::tсправа) - в результате
xэффективно набираетd(илиt, в зависимости от настроения унификации)
Проблема: x должен, очевидно, иметь тип Uint, но я не вижу, чтобы эти двое могли объединяться для создания типа. Существует потеря информации, когда тип test закрывается, и экземпляр снова появляется, что я не уверен, как преодолеть или подключиться к подстановкам/унификации.
Любая идея, как алгоритм должен быть исправлен для корректной печати x::Uint? Или это свойство системы HM и просто не будет вводить такой случай (что я сомневаюсь)?
Обратите внимание, что это было бы вполне нормально со стандартным let, но я не хотел обфускать пример с помощью рекурсивных определений, которые невозможно обработать с помощью let.
Заранее спасибо