Бег
type expression =
| Num of int
| Var of string
| Let of string * expression * expression
| Binop of string * expression * expression;;
в одном сеансе utop занимает примерно 8 секунд.
Теперь, если мы перейдем к отдельному сеансу utop и запустим
type expression =
| Num of int
| Var of string
| Let of string * expression * expression * expression * expression
| Binop of string * expression * expression;;
Это занимает около 13 секунд.
Наконец, давайте сделаем оба в одном сеансе
type expression =
| Num of int
| Var of string
| Let of string * expression * expression
| Binop of string * expression * expression;;
type expression_1 =
| Num of int
| Var of string
| Let of string * expression_1 * expression_1 * expression_1 * expression_1
| Binop of string * expression_1 * expression_1;;
Первый тип занимает 8 секунд, как и в отдельном сеансе, но прежняя 13-секундная операция теперь составляет 3 секунды! Что тут происходит?
Я очень мало знаю обо всей работе, которую OCaml выполняет с типами под капотом; возможно, он может построить дерево с 4 выражениями из дерева с 2 выражениями с помощью некоторого интеллектуального кэширования?
Или это что-то более сложное?
Например, поскольку мой пользовательский тип имеет рекурсивные компоненты в обоих случаях, проверяет ли он, имеют ли expression_1
и expression
какое-то «структурное» сходство? По мере того, как компилятор аннотирует и унифицирует типы в программе, у него может быть пара вариантов (без каламбура), когда он сталкивается с новым типом: использует ли он явно предопределенные типы, которые аннотируются как подсказки чтобы вывести тип под рукой, или он проходит через типы, о которых он знает, а затем настраиваемые типы, которые я определил?
Компилятор сначала оценивает какой-то тип, а затем придумывает представление, чтобы проверить, является ли он определенным типом? В этом примере он строит рекурсивную структуру всех expression * expression
... в дерево?
Я действительно не знаю, но я хочу узнать!