开发者

invoking functions defined by flet in another function

开发者 https://www.devze.com 2023-03-24 17:01 出处:网络
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 def

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号