invoking functions defined by flet in another function
I have a collection of functions defined in foo
that I want to also want to use in bar
. I have these functions defined in foo
because I want foo
to be self-contained -- otherwise I know that I can define these functions externally (globally) to be accessible to foo
and bar
and other functions, or define both foo
and bar
within a labels
construct in which these functions are defined only for foo
and bar
. In any case, I would like for foo
to be distributable without the external functions or the labels
structure. Hence the challenge.
This is what I have so far (I am using Emacs Lisp in this case), but what I have now ends up defining the local functions in foo
globally when I invoke bar
. Any suggestions how to define local variables/functions in bar
"on the fly"?
(defun foo (x)
(flet ((addone (x) (1+ x))
(addtwo (x) (+ 2 x)))
(addtwo x)))
(defun bar (x)
(let* ((fnlist (car (cdaddr (symbol-function 'foo))))
(nfn (length fnlist))
(ifn nil)
(bar-body '(addone x))
(i 0))
(eval (append
;; local symbol names
;; to which function definitions will be set
(list 'let (mapcar 'car fnlist))
开发者_如何学JAVA ;; set function definitions
(list '(while (< i nfn)
(setq ifn (nth i fnlist))
(eval `(fset ',(car ifn) ,(append (list 'lambda) (cdr ifn))))
(setq i (1+ i))))
;; function invocation
(list bar-body)))))
Function application:
(foo 1) ;;=> 3
(bar 1) ;;=> 2
(addone 1) ;;=> 2 ?should not be defined outside of bar?
This isn't self-contained, so it's not really an answer; but it's different to the other options you mentioned, so I'll add it anyway.
(defmacro with-foo-functions (&rest forms)
`(flet ((addone (x) (1+ x))
(addtwo (x) (+ 2 x)))
,@forms))
(defun foo (x)
(with-foo-functions
(addtwo x)))
(defun bar (x)
(with-foo-functions
(addone x)))
Emacs Lisp has dynamic binding. This is different from the lexical binding used by pretty much all other Lisps. For example, if you try to do the following in Common Lisp, you will get an error message saying that FOO
is not defined:
(defun bar ()
(foo 10))
(flet ((foo (x) (1+ x)))
(bar))
In Emacs Lisp, however, since FOO is dynamically bound this will return 11 as the binding of FOO
is available in BAR
.
Emacs Lisp does not provide lexical bindings for functions, so in order to achieve the same thing in Emacs Lisp you'll have to fake it by binding a lambda to a lexical variable and then use a macro to hide the FUNCALL
:
(lexical-let ((foo #'(lambda (x) (1+ x))))
(macrolet ((foo (x) `(funcall foo ,x)))
(foo 10)))
The other answer to this question suggests the use of a macro instead of the flet
. This works, but it results in unnecessary code duplication. My solution prevents this at the expense of having to either write the macrolet
part, or using funcall
every time you want to call the function. One could write a macro to wrap all of this inside a lexical flet
version if this is something that is needed often.
精彩评论