LISP动态定义函数

时间:2014-04-09 23:18:14

标签: function lisp definition

我想用一个参数来定义一个函数,该参数定义了另一个以该参数作为名称的函数。

不工作的例子:

(DEFUN custom (name op const var)
  (DEFUN name (var) (op const var)))

问题是名称未经评估,因此定义的函数始终称为名称。

我知道FUNCALLAPPLY可以动态评估参数,但我不知道如何正确调用FUNCALL DEFUN...

3 个答案:

答案 0 :(得分:4)

我认为你不能使用嵌套的defuns。

您可以使用defun返回lambda

(defun custom (op const) 
  (lambda (arg) (funcall op const arg)))

然后使用fdefinition

(setf (fdefinition '+42) (custom '+ '42))

或使用defmacro

(defmacro custom (name op const)
  (let ((arg (gensym)))
    `(defun ,name (,arg)
       (,op ,const ,arg))))

(custom +42 + 42)

PS。我认为您需要解释为什么要这样做,然后我们将能够更好地解释您的选择。

答案 1 :(得分:1)

在我看来,你可能想要一个功能。想象一下,你这样做了:

(defun curry (op arg1)
  (lambda (&rest args) (apply op (cons arg1 args))))

(funcall (curry #'+ 10) 20)        ; ==> 30 

(mapcar (curry #'+ 10) '(1 2 3 4)) ; ==> (11 12 13 14)

现在defun始终在全局命名空间中生成一个函数。它不像在Scheme中创建一个闭包。要与defun执行相同操作,我们使用symbol-functionsetf

(defun create-curried (name op arg1)
  (setf (symbol-function name) 
        (lambda (&rest args) (apply op (cons arg1 args)))))

(create-curried '+x #'+ 10) ; ==> function
(+x 20)                     ; ==> 30

;; since it's a function, it even works with higher order functions
(mapcar create-curried '(+x -x /x *x) (list #'+ #'- #'/ #'*) '(10 10 10 10))
(/x 2) ; ==> 5

最后。使用宏,你可以美化它。

(defmacro defun-curried (newname oldname arg)
  (if (and (symbolp newname) (symbolp oldname))
      `(create-curried ',newname (function ,oldname) ,arg)
      (error "Newname and Oldname need to be symbols")))

(defun-curried +xx + 20)
(+xx 10) ; ==> 30

oldname取自词汇范围,因此您可以使用fletlabels,但它最终是全局的,就像使用defun一样。

答案 2 :(得分:1)

主要问题是DEFUN不是函数,它是一个专门处理其参数的宏(具体来说,它没有评估"函数名称" ;,"参数列表",而不是"函数体")。

你可以通过谨慎使用(setf (symbol-function ...) ...)来制作一些东西,比如:

(defun define-custom-function (name op const)
   (setf (symbol-function name) (lambda (var) (funcall op const var))))

这会将符号的函数定义绑定到一个匿名函数,该函数调用您的"运算符"在你的输入常数。

* (defun define-custom-function (name op const)
       (setf (symbol-function name) (lambda (var) (funcall op const var))))

DEFINE-CUSTOM-FUNCTION
* (define-custom-function 'add3 #'+ 3)

#<CLOSURE (LAMBDA (VAR) :IN DEFINE-CUSTOM-FUNCTION) {1002A4760B}>
* (add3 5)

8

但是,除非您绝对需要动态定义(或重新定义)这些自定义函数,否则最好定义一个自定义DEFUN - 就像宏一样。