Одной из тенденций в компиляции является использование типизированных промежуточных языков. Haskell ghc
с его промежуточным языком core
, вариантом системы F-omega, является примером этой архитектуры [1]. Другим является LLVM, который имеет типичный промежуточный язык в своем ядре [2]. Преимущество этого подхода заключается в том, что ошибки в преобразованиях, составляющих части генератора кода, могут быть обнаружены на ранней стадии. Кроме того, информация о типе может использоваться во время оптимизации и генерации кода.
Для эффективности типизированные IR проверяются по типу, а не выводятся их типы. Чтобы быстро выполнять проверки типов, каждая переменная и каждое связующее несут типы для простой проверки типов.
Однако многие преобразования в конвейере компилятора могут вводить новые переменные. Например, преобразование нормализации K(.)
может преобразовать приложение
M(N)
в выражение типа
let x = K(M) in
let y = K(N) in x(y)
Вопрос. Интересно, как компиляторы справляются с проблемой предоставления типов новым
переменные. Повторяются ли они в примере выше K(M)
и K(N)
? Разве это не занимает много времени? И требуется ли окружающая среда? Используют ли они карты из узлов AST для ввода информации, чтобы избежать повторной проверки типов?
- S
. Марлоу, С. Пейтон Джонс, Компилятор Glasgow Haskell.