Я намагаюся перетворити мій код на використання лексичної прив'язки.
У мене є функція ( format-template
), яка викликає лямбда-функцію (прив'язка до заміни-внутрішньої
) зі списку, що настроюється користувачем ( шаблон-заміна -функцій
) функцій, заснованих на комбінаційній рядку. Функція-замінник-внутрішня не приймає аргументів і повертає рядок, проте може використовувати змінні foo
бар
та/або baz
, які передаються як частина аргументу list
до format-template
.
(setq lexical-binding t)
(defcustom template-replace-functions
'(("email"
(lambda() user-mail-address)
("apples"
(lambda ()
(cond ((= foo 1)
"one")
((= foo 2)
"two")
((= foo 3)
"three")
(t "four"))))
("bananas"
(lambda ()
(if (eq bar 'move)
"movement" "sit still")))))
"Association list of replacement functions.
For each STRING, the corresponding FUNCTION is called with no
arguments and must return a string."
:type '(repeat (group string function))
:group 'spice-girls)
(defun format-template (list)
(let* ((foo (nth 0 list))
(bar (nth 1 list))
(baz (nth 2 list))
template
(replacer-outer
(lambda ()
(replace-regexp-in-string
"\${\([^\s\t\n]*?\)}"
(lambda (match)
(let* ((key (match-string 1 match))
(replacer-inner
(cadr (assoc key template-replace-functions))))
(if (and replacer-inner
(stringp (funcall replacer-inner)))
(funcall replacer-inner) "")))
template t t))))
(setq template
...)
(if template (funcall replacer-outer))))
Так, наприклад, список
містить три елементи, які прив'язані до foo
bar
і baz
. ключ
рядка збігу є "bananas"
, який асоціюється з функцією в template-replace-functions
і встановлює заміну внутрішній
для:
(lambda ()
(if (eq bar 'move)
"movement" "sit still"))
На цьому етапі вищезгадана лямбда-функція повинна знати bar
, що добре використовує динамічне зв'язування, але не дуже точне, використовуючи лексичну прив'язку.
Моє питання полягає в тому, як зробити це, щоб дозволити лямбда-функції, пов'язані з replacer-internal
, приймати значення прив'язки foo
бар
і baz
?
(Просто щоб збентежити речі, функція replace-outer
, яка містить replace-internal
, призначена для прив'язки, оскільки вона викликається з одного з двох місць у реальній функції. Я міг би писати вбудовано тут, але включив його таким чином у випадку, якщо це додасть проблеми.)
Редагувати:
На півдорозі...
(setq lexical-binding t
foo 0
bar 0)
(setq inline-fun-1
'(lambda ()
(setq return
(if (eq foo 1)
"Pass" "Fail"))))
(defmacro lex-fun ()
`(let* ((foo 1)
(bar 1)
return)
(funcall ,inline-fun-1)))
(lex-fun) ; -> "Pass"
(defun inline-fun-2 ()
(setq return
(if (eq bar 1)
"Pass" "Fail")))
(defmacro lex-fun ()
`(let* ((foo 1)
(bar 1)
return)
(funcall ,inline-fun-2)))
(lex-fun) ; -> Lisp error: (void-variable inline-fun-2)
Таким чином, розширення функції лямбда в межах макросу з'являється на роботу, але не на ім'я функції. Але я хочу, щоб дозволити користувачеві лямбда або названі функції. Як обійти це?