Это - главным образом продолжение этого вопроса. Я решил просто иметь в виду YAGNI и создал глобальную переменную (libpython
). Я установил его на #f
первоначально, затем set!
это, когда init
назван. Я добавил функцию, которая должна обработать проверку, если то значение было инициализировано:
(define (get-cpyfunc name type)
(lambda args
(if libpython
(apply (get-ffi-obj name libpython type) args)
(error "Call init before using any Python C functions"))))
Таким образом, теперь вот то, что я хочу сделать. Я хочу определить макрос, который возьмет следующее:
(define-cpyfunc Py_Initialize (_fun -> _void))
И преобразуйте его в это:
(define Py_Initialize (get-cpyfunc "Py_Initialize" (_fun -> _void)))
Я прочитывал макро-документацию, чтобы попытаться понять это, но я, может казаться, не выясняю способ заставить ее работать. Кто-либо может помочь мне с этим (или по крайней мере дать мне общее представление о том, на что макрос был бы похож)? Или есть ли способ сделать это без макросов?
Я ответил на большую часть этого вопроса в другой теме (эту я не видел). Использовать функцию, которая извлекает привязки таким образом, вполне нормально, но одна из возможных проблем здесь заключается в том, что поскольку вы создаете привязку только при вызове результирующей функции, эта привязка создается заново при каждом вызове. Простой способ быстро решить эту проблему - использовать обещания, что-то вроде этого:
(require scheme/promise)
(define (get-cpyfunc name type)
(define the-function
(delay (if libpython
(get-ffi-obj name libpython type)
(error "Call init before using any Python C functions"))))
(lambda args (apply (force the-function) args)))
Но по сути это почти то же самое, что и код, который я разместил в вашем предыдущем вопросе.
Еще случайные замечания:
get-ffi-obj
будет принимать символ в качестве имени для привязки - это сделано намеренно, чтобы упростить создание таких макросов (как в последнем вопросе).
Использование (symbol->string 'name)
в макросе - это нормально. Как я отметил выше в своем комментарии в ответ на комментарий Натана, это означает, что он вызывается во время выполнения, но mzscheme должен быть в состоянии оптимизировать это в любом случае, поэтому нет необходимости пытаться написать какой-то сложный макрос, который делает эту работу во время компиляции.
Загляните в каталог PLT - вы найдете коллекцию под названием ffi
. Это коллекция примеров связывания с различными стилями. Макросы, создающие привязки, очень часто встречаются в этих примерах.
Почему бы вам не изменить сгенерированный код на
(define Py_Initialize (get-cpyfunc 'Py_Initialize (_fun -> _void)))
, а затем запустить get-cpyfunc
(символ-> имя строки)
?
Конечно, вероятно, есть способ сделать это с помощью syntax-case
(хотя я никогда не могу вспомнить его синтаксис ), и определенно, если вы используете схему с CL -esque определение макроса
.
Это не полный ответ, но я придумал макрос, который удовлетворяет обоим требованиям (определяет переменную и строку с именем этой переменной):
> (define-syntax (my-syntax stx)
(syntax-case stx ()
[(_ id)
#'(define-values (id) (values (symbol->string (quote id))))]))
> (my-syntax y)
> y
"y"