Пользовательские типы в OCaml и памяти

Бег

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... в дерево?

Я действительно не знаю, но я хочу узнать!


person ofey73    schedule 20.08.2019    source источник


Ответы (1)


В своем эксперименте вы измеряете не OCaml, а интерактивный интерпретатор OCaml utop. Хотя цифры, которые вы показываете, действительно возмутительны и необычны, они не имеют ничего общего с производительностью OCaml. Они указывают на то, что с вашей системой что-то не так.

Говоря об OCaml, он имеет чрезвычайно производительный компилятор, способный вводить тысячи выражений в миллисекунду, поэтому вы вряд ли сможете его заметить. Фактически, OCaml часто используется в качестве целевого языка для различных языков более высокого уровня и средств доказательства теорем, таких как Coq, Ott и F*, поэтому он используется для компиляции сгенерированного машиной кода, которого обычно много.

Возвращаясь к вашему примеру, я подозреваю, что вы либо запускаете utop в папке с большим количеством файлов, либо ваш файл .ocamlinit выполняет какие-то медленные вычисления, либо вы не описываете нам свой эксперимент полностью. Или вы наткнулись на какую-то ошибку в utop.

Я также могу предложить поиграть с down новой библиотекой верхнего уровня для OCaml. Например, (первый символ - подсказка)

$ ocaml
# #use "topfind";;
# #require "down";;

Или просто запустите ocaml с помощью rlwrap, например,

$ rlwrap ocaml

Или даже попробуйте OCaml в своем браузере1.

Кроме того, если вы хотите узнать, что OCaml делает с вашими определениями типов — ничего сложного, просто анализирует их и выполняет некоторые проверки работоспособности. Ничего, что могло бы занять больше доли секунды, даже 30 лет назад.


1)) В этом случае сам компилятор OCaml скомпилирован в Javascript и запускается вашим браузером, и он все равно примет ваши определения за миллисекунды.

person ivg    schedule 21.08.2019