вызов функций, определенных с помощью flet, в другой функции - PullRequest
0 голосов
/ 31 июля 2011

У меня есть набор функций, определенных в foo, которые я также хочу использовать в bar. У меня есть эти функции, определенные в foo, потому что я хочу, чтобы foo был автономным - иначе я знаю, что могу определить эти функции внешне (глобально), чтобы они были доступны для foo и bar и других функций, или определите foo и bar в конструкции labels, в которой эти функции определены только для foo и bar. В любом случае, я бы хотел, чтобы 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 ]

2 голосов
/ 31 июля 2011

Это не самодостаточно, поэтому на самом деле это не ответ; но он отличается от других упомянутых вами вариантов, поэтому я все равно добавлю его.

(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 голос
/ 01 августа 2011

Emacs Lisp имеет динамическое связывание.Это отличается от лексического связывания, используемого почти всеми другими Лиспами.Например, если вы попытаетесь сделать следующее в Common Lisp, вы получите сообщение об ошибке, в котором говорится, что FOO не определено:

(defun bar ()
  (foo 10))

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

В Emacs Lisp, однако, поскольку FOO динамически связывает этовернет 11, так как привязка FOO доступна в BAR.

Emacs Lisp не предоставляет лексических привязок для функций, поэтому для достижения того же самого в Emacs Lisp вам придется подделатьэто связывание лямбды с лексической переменной, а затем использование макроса для сокрытия FUNCALL:

(lexical-let ((foo #'(lambda (x) (1+ x))))
  (macrolet ((foo (x) `(funcall foo ,x)))
    (foo 10)))

Другой ответ на этот вопрос предполагает использование макроса вместо flet.Это работает, но это приводит к ненужному дублированию кода.Мое решение предотвращает это за счет необходимости либо писать часть macrolet, либо использовать funcall каждый раз, когда вы хотите вызвать функцию.Можно написать макрос, чтобы обернуть все это в лексическую версию flet, если это часто требуется.

...