Там должен так или иначе реализовать Ресурс, Acquisation является Инициализация в Схеме?
Я знаю, что RAII не работает хорошо на языках редактора GC (так как мы понятия не имеем whe, объект уничтожается). Однако Схема имеет хорошие вещи как продолжения, динамический ветер, и закрытия - являются там способом использовать некоторую комбинацию этого для реализации RAII?
В противном случае, как интриганы разрабатывают свой код для не использования RAII?
[Типичный пример, с которым я сталкиваюсь, следующий:
У меня есть 3D сетка, у меня есть Буферный Объект Вершины, присоединенный к ней, когда Сетка больше не используется, я хочу VBO, освобожденный.]
Спасибо!
Если это всего лишь разовая, вы всегда можете просто написать макрос, который обернутся вокруг динамического ветра
, выполняя настройку и разрыв в ранее и после Thunks (Я предполагаю, что выделение-вершина-буферный объект
и и
Buffer-Object
- ваш конструктор и деструкторы здесь):
(define-syntax with-vertex-buffer-object
(syntax-rules ()
((_ (name arg ...) body ...)
(let ((name #f))
(dynamic-wind
(lambda () (set! name (allocate-vertex-buffer-object args ...)))
(lambda () body ...)
(lambda () (free-vertex-buffer-object name) (set! name #f)))))))
Если это шаблон, который Вы используете много, для разных типов объектов, вы можете написать макрос для генерации такого рода макроса; И, скорее всего, вы собираетесь выделить серию этих одновременно, поэтому вы можете захотеть иметь список привязки в начале, а не только один.
Вот манжета, большая общая версия; Я не совсем уверен в имени, но он демонстрирует основную идею (, отредактированную для фиксации бесконечного цикла в оригинальной версии ):
(define-syntax with-managed-objects
(syntax-rules ()
((_ ((name constructor destructor)) body ...)
(let ((name #f))
(dynamic-wind
(lambda () (set! name constructor))
(lambda () body ...)
(lambda () destructor (set! name #f)))))
((_ ((name constructor destructor) rest ...)
body ...)
(with-managed-objects ((name constructor destructor))
(with-managed-objects (rest ...)
body ...)))
((_ () body ...)
(begin body ...))))
, и вы будете использовать это следующим образом:
(with-managed-objects ((vbo (allocate-vertex-buffer-object 1 2 3)
(free-vertext-buffer-object vbo))
(frob (create-frobnozzle 'foo 'bar)
(destroy-frobnozzle frob)))
;; do stuff ...
)
Вот пример Это демонстрирует его работу, в том числе выходящие и повторные ввози в объем с использованием продолжений (это довольно надуманный пример, извинения, если поток управления немного трудно следовать):
(let ((inner-continuation #f))
(if (with-managed-objects ((foo (begin (display "entering foo\n") 1)
(display "exiting foo\n"))
(bar (begin (display "entering bar\n") (+ foo 1))
(display "exiting bar\n")))
(display "inside\n")
(display "foo: ") (display foo) (newline)
(display "bar: ") (display bar) (newline)
(call/cc (lambda (inside) (set! inner-continuation inside) #t)))
(begin (display "* Let's try that again!\n")
(inner-continuation #f))
(display "* All done\n")))
Это должно распечатать:
entering foo entering bar inside foo: 1 bar: 2 exiting bar exiting foo * Let's try that again! entering foo entering bar exiting bar exiting foo * All done
Call / CC
- это просто аббревиатура call-с текущей продолжением
; Используйте более длинную форму, если ваша схема не имеет более короткой.
Обновление : Как вы уточнили в ваших комментариях, вы ищете способ управлять ресурсами, которые можно вернуть из определенного динамического контекста. В этом случае вам придется использовать финализатор; Финализатор - это функция, которая будет вызываться с вами объектом после того, как GC доказал, что его нельзя добраться из-за чего-либо еще. Учетные финализаторы не являются стандартными, но большинство зрелых систем схемы у них есть, иногда под разными именами. Например, в схеме PLT см. Wills и Executors .
Вы должны помнить, что на схеме, динамический контекст может быть повторно введен; Это отличается от большинства других языков, в которых вы можете выйти из динамического контекста в любой произвольной точке с использованием исключений, но вы не можете войти в систему. В моем примере выше, я продемонстрировал наивный подход к использованию динамического ветра
, чтобы освободить ресурсы, когда вы оставляете динамический контекст, и повторно выделите их, если вы вводите снова. Это может быть подходящим для некоторых ресурсов, но для многих ресурсов было бы не подходящим (например, повторно открытие файла, вы теперь будете в начале файла при повторном входе в динамический контекст) и могут иметь значительный накладной расход.
Тейлор Кэмпбелл (да, есть отношение) имеет статью статьи в его BLAG (вступление в 2009-03-28), посвященную этому вопросу и представляя несколько альтернатив на основе точной семантики, которую вы хочу. Например, он обеспечивает форму Warmnind-Protext
, которая не будет вызывать процедуру очистки до тех пор, пока не будет невозможно повторно ввести динамический контекст, в котором доступный ресурс.
Итак, это охватывает много разных вариантов, которые доступны. Нет точного совпадения для Raii, поскольку схема является очень другим языком и имеет очень разные ограничения. Если у вас есть более конкретный случай для использования или более подробной информации о случаях использования, который вы кратко упоминали, я могу предоставить вам еще несколько конкретных советов.