【问题标题】:LISP dynamically define functionsLISP 动态定义函数
【发布时间】:2014-04-09 23:18:14
【问题描述】:

我想定义一个带有参数的函数,该参数定义了另一个以该参数为名称的函数。

不起作用的例子:

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

问题是 name 没有被评估,所以定义的函数总是被称为 name。

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

【问题讨论】:

  • 你能举例说明你想如何使用它吗?实际代码最好。

标签: function lisp definition


【解决方案1】:

我认为你不能使用嵌套的 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。我认为您需要解释为什么要这样做,然后我们才能更好地解释您的选择。

【讨论】:

    【解决方案2】:

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

    (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 一样。

    【讨论】:

      【解决方案3】:

      主要问题是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-like 宏。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        相关资源
        最近更新 更多