Запуск кода только один раз в библиотеке OCaml - PullRequest
4 голосов
/ 06 мая 2011

Я пишу библиотеку OCaml, в которой есть некоторый код инициализации, который должен быть запущен только один раз за время существования программы с использованием библиотеки (и хранит некоторое состояние, которое будет сохраняться в течение всего срока действия программы, но использоваться только внутрисамой библиотеки) и некоторый код очистки, который необходимо запускать только при выходе из программы, использующей библиотеку.

Если это уместно, моя библиотека состоит из двух частей: интерфейса с низкоуровневой библиотекой C и некоторых высокоуровневых вещей, облегчающих программирование.Могу ли я сделать то, что мне нужно где-то в C?В идеале моим пользователям было бы все равно, как это реализовано, они никогда не увидят биты C.

В Python я бы сделал это, запустив код на import, но на open в OCaml.на самом деле ничего не запускается, он просто подслащивает пространство имен модуля, а затем Python atexit, но я не могу найти эквивалент Ocaml.

Один из подходов, который я рассмотрел, - это структурирование моей библиотеки как "фреймворка"«Но я не думаю, что это достаточно важно, чтобы оправдать такой чрезмерно продуманный подход.Спасибо!

ОБНОВЛЕНИЕ : ОК, понял - думаю.Я использую код C для обработки очистки при выходе, и я немного манипулировал кодом, чтобы на стороне C был указатель на глобальное состояние

Это будет , чтов моей библиотеке у меня теперь есть

let global_env = env_create ()

И когда оно open d основной программой, это запускается ... Но как?

Ответы [ 2 ]

7 голосов
/ 06 мая 2011

Обратите внимание, что это можно сделать на стороне OCaml с помощью Pervasives.at_exit и операторов верхнего уровня для создания среды и установки кода очистки:

let env = init ()
let cleanup () = do_clean env
let () = at_exit cleanup 

let f x = f_stub env x

Операторы верхнего уровнявыполняются, когда модуль загружен (независимо от того, используете ли вы его в конечном итоге или нет) и модули загружаются в порядке, указанном вами во время соединения (таким образом, модули, зависящие от других, гарантируют, что их зависимости инициализируются, когда наступает их очередь), см. "Аргументы, заканчивающиеся на .cmo "в руководстве ocamlc .Это влечет за собой выполнение операторов верхнего уровня перед тем, как вы попытаетесь получить доступ к модулю.Не нужно открывать модуль, open - просто (плохое) синтаксическое удобство.

Если вы хотите, чтобы код инициализации выполнялся тогда и только тогда, когда функция модуля в конечном итоге вызывается, используйте ленивое значение:

let env = lazy (init ())
let cleanup () = if Lazy.lazy_is_val env then (do_clean env) else () 
let () = at_exit cleanup

let f x = f_stub (Lazy.force env) x

Кстати.не забудьте задокументировать возникшие проблемы с безопасностью потоков ...

1 голос
/ 06 мая 2011

Так же, как let x = function ... определяет функцию x, которая доступна с этой точки и далее ваш let global_env = ... определяет значение global_env. Если вы этого не сделаете нужно возвращаемое значение env_create, потому что вы запускаете его только для его побочных эффектов, Вы также можете упомянуть env_create () в конце (если честно, в любом месте) мл файл. В этом случае я бы сделал let _ = env_create (), что, на мой взгляд, более явно.

РЕДАКТИРОВАТЬ : R указал, что следующее неправильно: «Чтобы сделать это чисто на C, я думаю, что _init и _fini - это то, что нужно искать». Как объяснено в этом HOWTO , оно действительно устарело и теперь должно выполняться через атрибуты.

...