Подтвердить что ты не робот

Что происходит с отсутствующими переменными типа в ядре церковного стиля?

Это немного эзотерическое, но безумное. В ответе на еще один вопрос я отметил, что в этой полностью действующей программе

poo :: String -> a -> a
poo _ = id

qoo :: (a -> a) -> String
qoo _ = ""

roo :: String -> String
roo = qoo . poo

переменная типа a не решается и не обобщается в процессе проверки roo. Мне интересно, что происходит в переводе на основной язык GHC, вариант в стиле церкви System F. Позвольте мне прочесть вещи из рук в руки, с явным типом lambdas /\ и типами приложений @.

poo :: forall a. [Char] -> a -> a
poo = /\ a -> \ s x -> id @ a

qoo :: forall a. (a -> a) -> [Char]
qoo = /\ a -> \ f -> [] @ Char

roo :: [Char] -> [Char]
roo = (.) @ [Char] @ (? -> ?) @ [Char] (qoo @ ?) (poo @ ?)

Что происходит в местах ?? Как roo становится допустимым ключевым термином? Или мы действительно получаем загадочный пустой квантификатор, несмотря на то, что говорит подпись типа?

roo :: forall a. [Char] -> [Char]
roo = /\ a -> ...

Я только что проверил, что

roo :: forall . String -> String
roo = qoo . poo

проходит через ok, что может или не означает, что вещь typechecks без дополнительной квантификации.

Что там происходит?

4b9b3361

Ответ 1

Здесь ядро ​​сгенерировано GHC (после добавления некоторых NOINLINE прагм).

qoo_rbu :: forall a_abz. (a_abz -> a_abz) -> GHC.Base.String
[GblId, Arity=1, Caf=NoCafRefs]
qoo_rbu = \ (@ a_abN) _ -> GHC.Types.[] @ GHC.Types.Char

poo_rbs :: forall a_abA. GHC.Base.String -> a_abA -> a_abA
[GblId, Arity=1]
poo_rbs = \ (@ a_abP) _ -> GHC.Base.id @ a_abP

roo_rbw :: GHC.Base.String -> GHC.Base.String
[GblId]
roo_rbw =
  GHC.Base..
    @ (GHC.Prim.Any -> GHC.Prim.Any)
    @ GHC.Base.String
    @ GHC.Base.String
    (qoo_rbu @ GHC.Prim.Any)
    (poo_rbs @ GHC.Prim.Any)

Кажется, что GHC.Prim.Any используется для полиморфного типа.

Из документы (внимание мое):

Конструктор типа Any - это тип, к которому вы можете поднятый тип и назад.

  • Поднимается и, следовательно, отображается указателем
  • Он не претендует на быть типом данных, и это важно для генератора кода, потому что код gen может ввести значение данных, но никогда не вводит значение функции.

Он также используется для создания экземпляров без ограничений типа после типа проверка.

Имеет смысл иметь такой тип для вставки вместо не-ограниченных типов, поскольку в противном случае тривиальные выражения, такие как length [], вызывают неоднозначную ошибку типа.

Ответ 2

Это не проблема. В сигнатуре roo переменная типа a просто не отображается, как она есть. Более простым примером могло бы быть выражение

const 1 id

где

id :: forall a.a->a