Как можно распечатать значения OCaml за пределами верхнего уровня?
OCaml repl ("toplevel") имеет расширенную печать для любых типов, определенных пользователем или иным образом. Возможно ли получить доступ к этой функциональности за пределами верхнего уровня, вместо того, чтобы писать совершенно собственный набор принтеров значений для своего полного набора типов?
4 ответа
Средство красивой печати является частью библиотеки верхнего уровня. Вы найдете источник в toplevel/genprintval.ml
, Это понятно, учитывая, что ему нужна информация о типе: вы не можете просто указать какое-либо значение, выбор симпатичного принтера зависит от типа.
Если вы хотите использовать этот код в своей программе, вам нужно будет связать его с библиотекой верхнего уровня (toplevellib.cma
) или скомпилировать в genprintval
(что означает введение достаточного количества битов проверки типов для анализа типа, он может стать довольно большим).
В отладчике есть похожая возможность (но я не разделяю код, я думаю) debugger/printval.ml
а также debugger/loadprinter.ml
).
Существуют сторонние библиотеки, с которыми вы можете напрямую связываться, и которые предоставляют удобные средства печати. Extlib Std.dump
обеспечивает очень грубое средство (не в зависимости от типа). Вывод Джереми Яллопа и Джейка Донхэма - другой подход. Этот еженедельный новостной материал Caml предлагает больше предложений.
Библиотека аккумуляторов OCaml содержит dump
функция в своем модуле BatPervasives. Он преобразует любое значение в строку и возвращает его. Вы можете увидеть его исходный код здесь. Выходные данные не будут идентичны верхнему уровню, потому что некоторая информация теряется во время выполнения, например, конструкторы абстрактных типов данных станут целыми числами.
Начиная с OCaml 4.06, компилятор не делает информацию о типе доступной во время выполнения. Поэтому невозможно иметь автономные программы, которые красиво печатают любые данные OCaml без каких-либо компромиссов. Два основных направления:
- Некоторая форма предварительной обработки, которая выводит принтеры из определений типов. Сегодня лучшим подходом может быть плагин show для получения ppx. Это требует аннотирования каждого определения типа.
- Опираясь только на представление значений во время выполнения. Это не требует усилий со стороны программиста и работает "из коробки" с данными, создаваемыми внешними библиотеками. Однако он не показывает такие вещи, как имена полей записей или любую другую информацию, которая была потеряна во время компиляции. Пример такого подхода подробно описан ниже.
Функция Dum.to_stdout
из пакета dum возьмет любое значение OCaml, включая циклическое, и напечатает их физическое представление в удобочитаемой форме с учетом данных, доступных только во время выполнения.
Простые вещи дают более или менее то, что можно ожидать:
# Dum.to_stdout ("Hello", 42, Some `Thing, [1;2;3]);;
("Hello" 42 (582416334) [ 1 2 3 ])
Циклические и в общем случае общие значения отображаются с использованием меток и ссылок. Это круговой список:
# let rec cyc = 1 :: 2 :: cyc;;
# Dum.to_stdout cyc;;
#0: (1 (2 #0))
Мы также можем посмотреть во время выполнения представление функций, модулей и других вещей. Например, Filename
Модуль может быть проверен следующим образом:
# module type Filename = module type of Filename;;
# Dum.to_stdout (module Filename : Filename);;
(
#0: "."
".."
#1: "/"
#2: closure (#1 #3: closure ())
#4: closure ()
closure (#4)
closure ()
closure ()
closure (#5: closure (#3))
closure (#5)
closure (#5)
closure (closure () #3 #0)
closure (closure () #3 #0)
closure (#6: closure (#2 <lazy>) #7: (#8))
closure (#6 #7)
closure (#7)
closure (#7)
#8: "/tmp"
closure (closure () "'\\''")
)
Я знаю, что вы хотите это за пределами верхнего уровня, но я думаю, что стоит упомянуть, как это сделать на верхнем уровне, чтобы люди все равно искали печать (поскольку кажется, что за пределами верхнего уровня это не тривиально):
- загрузите файл на верхнем уровне
utop
#use "datatypes.ml";;
- затем «вызовите» переменную внутри верхнего уровня:
utop # let nada = Nothing;;
utop # nada;;
- : foo = Nothing
ссылка: https://discuss.ocaml.org/t/how-does-one-print-any-type/4362/16?u=brando90