Consider this question. Here the basic problem is the code:
(progv '(op arg) '(1+ 1)
(eval '(op arg)))
The problem here is that progv
binds the value to the variable as variable's symbol-value
not symbol-function
. But, that's obvious because we didn't explicitly suggest which values are functions.
So, in order to solve this problem, I thought of manually dynamically binding the variables, to their values based on the type of values. If the values are fboundp
then they should be bound to the symbol-function
of the variable. A restriction, is that match-if
can't be a macro
. It has to be a function
, because it is called by a funcall
.
Macro : functioner
:
(defmacro functioner (var val)
`(if (and (symbolp ',val)
(fboundp ',val))
(setf (symbol-function ',var) #',val)
(setf ,var ,val)))
Function: match-if
:
(defun match-if (pattern input bindings)
(eval `(and (let ,(mapcar #'(lambda (x) (list (car x))) bindings)
(declare (special ,@ (mapcar #'car bindings)))
(loop for i in ',bindings
do (eval `(functioner ,(first i) ,(rest i))))
(eval (second (first ,pattern))))
(pat-match (rest ,pattern) ,input ,bindings))))
Here, the let
part declares all the variables lexically (supposedly). Then declare
declares them special
. Then functioner
binds the variables and their values aptly. Then the code in the pattern is evaluated. If the code part is true, then only the pattern-matcher function pat-match
is invoked.
The problem is that in the function, all it's arguments are evaluated. Thus bindings
in the let
and declare
parts will be replaced by something like :
((v1 . val1)(v2 . val2)(v3 . val3))
not
'((v1 . val1)(v2 . val2)(v3 . val3))
So, it's treated as code, not a list.
So, I'm stuck here. And macros won't help me on this one.
Any help appreciated.
Not the answer you are looking for, but PROGV
is a special operator; it is granted the ability to modify the dynamic bindings of variables at runtime; AFAIK, you can't simply hack it to operate on "dynamic function bindings".
The point of progv
is to use list of symbols and values that are evaluated, meaning that you can generate symbols at runtime and bind them dynamically to the corresponding values.
You might be able to find a solution with eval
but note that if you macroexpand into (eval ...)
, then you loose the surrounding lexical context, which is generally not what you want ("eval" operates on the null lexical environment). I speculate that you could also have a custom code walker which works on top-level forms but reorganizes them, when it finds your special operator, to bring the context back in, producing something like (eval '(let (...) ...))
.