在另一个函数中调用flet定义的函数

时间:2011-07-31 06:14:59

标签: lisp elisp

我在foo中定义了一系列我想要在bar中使用的函数。我在foo中定义了这些函数,因为我希望foo是自包含的 - 否则我知道我可以在外部(全局)定义这些函数,以便foo和{bar可以访问{1}}和其他函数,或在foo构造中定义barlabels,其中仅为foobar定义了这些函数。无论如何,我希望foo可以在没有外部函数或labels结构的情况下进行分发。因此挑战。

这是我到目前为止(在这种情况下我使用的是Emacs Lisp),但是当我调用foo时,我现在最终在全局bar中定义本地函数。有关如何在bar“动态”定义局部变量/函数的任何建议吗?

(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))
       ;; 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)))))

功能应用程序:

(foo 1) ;;=> 3

(bar 1) ;;=> 2

(addone 1) ;;=> 2 ?should not be defined outside of bar?

2 个答案:

答案 0 :(得分:2)

这不是独立的,所以它不是一个真正的答案;但它与你提到的其他选项不同,所以无论如何我都会添加它。

(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)))

答案 1 :(得分:1)

Emacs Lisp具有动态绑定功能。这与几乎所有其他Lisps使用的词法绑定不同。例如,如果您尝试在Common Lisp中执行以下操作,则会收到一条错误消息,指出FOO未定义:

(defun bar ()
  (foo 10))

(flet ((foo (x) (1+ x)))
  (bar))

然而,在Emacs Lisp中,由于FOO是动态绑定的,因此FOOBAR的绑定可用,因此返回11。

Emacs Lisp不为函数提供词法绑定,所以为了在Emacs Lisp中实现相同的功能,你必须通过将lambda绑定到词法变量来伪造它,然后使用宏来隐藏{{1 }}:

FUNCALL

此问题的另一个答案建议使用宏而不是(lexical-let ((foo #'(lambda (x) (1+ x)))) (macrolet ((foo (x) `(funcall foo ,x))) (foo 10))) 。这有效,但会导致不必要的代码重复。我的解决方案可以防止这种情况,因为每次要调用函数时都必须编写flet部分或使用macrolet。如果这是经常需要的东西,可以写一个宏来将所有这些包装在词法funcall版本中。