Ik probeer mijn code te converteren om lexicale binding te gebruiken.
Ik heb een functie ( format-template
) die een lambda-functie (let-bound to replacer-inner
) uit een door de gebruiker aan te passen lijst ( sjabloon-vervangt -functies
) van functies op basis van een match-string. De functie replacer-inner neemt geen argumenten aan en retourneert een tekenreeks, maar may moet variabelen foo
bar
en/of gebruiken baz
, die worden doorgegeven als onderdeel van het argument lijst
tot opmaaksjabloon
.
(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))))
Dus, bijvoorbeeld, lijst
bevat drie elementen, die zijn gebonden aan foo
bar
en baz
. De -code
van de overeenkomstreeks is "bananen"
die aan een functie in sjabloon-vervang-functies
koppelt en vervangt innerlijke
om:
(lambda ()
(if (eq bar 'move)
"movement" "sit still"))
Op dit punt moet de bovenstaande lambda-functie bar
kennen, wat prima is met behulp van dynamische binding, maar niet zo goed met lexicale binding.
Mijn vraag is, hoe kan ik dit doen om de lambda-functie gebonden aan replacer-inner
te laten nemen van de let-bound-waarden van foo
bar
en baz
?
(Gewoon om dingen te verwarren, de functie replace-outer
, die replace-inner
bevat, is let-bound omdat deze wordt aangeroepen vanuit een van de twee plaatsen in de echte functie. Ik zou hier inline kunnen hebben geschreven, maar ik heb het op deze manier toegevoegd voor het geval het aan het probleem toevoegt.)
Bewerken
Halverwege...
(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)
Dus uitbreiding van de lambda-functie binnen een macro lijkt te werken, maar geen functie met een naam. Maar ik wil de gebruiker lambda of benoemde functies toestaan. Hoe kom je hier omheen?