修改功能;保存到Lisp中的新功能 [英] Modifying function; saving to new function in lisp

查看:88
本文介绍了修改功能;保存到Lisp中的新功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

因此,我认为lisp的优点之一(除其他语言外)是其实现函数工厂的能力(接受函数作为参数;返回新函数).我想使用此功能对功能进行小的更改并将其保存为新功能,这样,如果对原始功能进行了更改,它们也将反映在该功能所基于的新功能中.注意:我不是编写原始函数的人,因此我不必将公共部分封装在一个单独的函数中,然后由两者调用,否则,这显然是答案.

emacs lisp中的玩具示例(可能不是最理想的lisp-2):

我有一个提供给我的函数foo:

(defun foo (x y)
    (+ x y)))

我希望我的新函数包含一个语句,如果满足特定条件,该语句允许我更改变量的值.例如:

(defun newfoo (x y)
  (if (condition-met-p x) 
      (setq x (transform x)))
    (+ x y))

请忽略我可以在此特定示例中使用defadvice,因为我对修改可能不适用defadvice的功能的一般任务更感兴趣.我相信我可以使用以下表单修改正文:

(setq conditional-transformation 
      '(if (condition-met x) (setq x (transform x))))

(setq newbody (append conditional-transformation 
              (nth 2 (symbol-function 'foo)))))

我的问题是具体如何

  1. 创建foonewfoo的副本 并用该值替换主体 上面定义的newbody的值. (我有 调查了fsetsetffunction,但也许不使用 他们正确地.)
  2. 可能将其包装在一个函数中 称为makenewfoo()之类的 这样我可以调用 makenewfoo(foo)并允许它 创建newfoo().

而且,更普遍的是

  1. 通常是这样的 完成或有更多惯用语 修改功能的方式?
  2. 这是一个非常简单的情况,但是 还有比这更一般的方法 指定列表元素编号 到nth进行修改.为了 例如,实际功能是 更复杂,有没有办法 递归搜索 s表达式树并测试a 特定语法并插入此 conditional-transformation 之前或之后的表达 (可能使用equal),因此 对所做的更改不太敏感 原始功能?

解决方案

它在Emacs Lisp中有效:

elisp> (defun foo (x y)
         (+ x y))
foo
elisp> (fset 'newfoo
             (append (lambda (x y)
                       (when (< x 2)
                         (setq x (* x 2))))
                     (cddr (symbol-function 'foo))))
(lambda
  (x y)
  (when
      (< x 2)
    (setq x
          (* x 2)))
  (+ x y))

elisp> (newfoo 1 3)
5
elisp> (newfoo 3 3)
6

但是我真的不认为这是通常做的或惯用的.如果要修改功能的行为,则应使用defadvice.

就CL而言:某些实现提供了类似的功能/宏(例如,在CCL中:ccl:advise),并且您可以为通用函数指定:before:after:around方法. /p>


用于插入表达式的示例代码:

(defun find-node (elt tree)
  (cond ((null tree) nil)
        ((equal (car tree) elt) tree)
        ((consp (car tree)) (let ((node (find-node elt (car tree))))
                              (if node node (find-node elt (cdr tree)))))
        (t (find-node elt (cdr tree)))))

(defun insert-before (node elt)
  (setcdr node (cons (car node) (cdr node)))
  (setcar node elt))

(let* ((function (copy-tree (symbol-function 'foo)))
       (node (find-node '(+ x y) function)))
  (when node
    (insert-before node '(if (< x 2) (setq x (* x 2))))
    (fset 'newfoo function)))

So I thought one of the advantages of lisp (among other languages) is its ability to implement function factories (accept functions as arguments; return new functions). I want to use this capability to make small changes to a function and save it as a new function so that if changes are made to the original function, they are also reflected in the new function on which it is based. Note: I am not the one writing the original function so I can't necessarily encapsulate the common parts in a separate function to be called by both, which would be the obvious answer otherwise.

Toy example in emacs lisp (may not be the most ideal as it is a lisp-2):

I have a function, foo that is provided to me:

(defun foo (x y)
    (+ x y)))

I want my new function to include a statement that allows me to change the value of a variable if a certain condition is met. For instance:

(defun newfoo (x y)
  (if (condition-met-p x) 
      (setq x (transform x)))
    (+ x y))

Please disregard that I could use defadvice in this particular example as I am more interested in the general task of modifying functions where defadvice may not apply. I believe I can modify the body with this form:

(setq conditional-transformation 
      '(if (condition-met x) (setq x (transform x))))

(setq newbody (append conditional-transformation 
              (nth 2 (symbol-function 'foo)))))

My questions are specifically how to

  1. create a copy of foo to newfoo and replace the body with the value of newbody defined above. (I've looked into fset, setf, and function but perhaps not using them properly.)
  2. possibly wrap this in a function called makenewfoo() or something like this so I can invoke makenewfoo(foo) and allow this to create newfoo().

And, more generally,

  1. is something like this is commonly done or there is a more idiomatic way to modify functions?
  2. this is a very simple case, but is there a more general way than specifying the list element number to nth for the modification. For instance, the actual function is more complex so is there a way to recursively search down this s-expression tree and test for a particular syntax and insert this conditional-transformation expression before or after it (possibly using equal), so it is less sensitive to changes made in the original function?

解决方案

It does work in Emacs Lisp:

elisp> (defun foo (x y)
         (+ x y))
foo
elisp> (fset 'newfoo
             (append (lambda (x y)
                       (when (< x 2)
                         (setq x (* x 2))))
                     (cddr (symbol-function 'foo))))
(lambda
  (x y)
  (when
      (< x 2)
    (setq x
          (* x 2)))
  (+ x y))

elisp> (newfoo 1 3)
5
elisp> (newfoo 3 3)
6

But I really don't think that it is commonly done or idiomatic. You should use defadvice if you want to modify the behavior of functions.

As far as CL is concerned: Some implementations provide similar functions/macros (for example in CCL: ccl:advise), and you can specify :before, :after, and :around methods for generic functions.


Example code for insertion of expressions:

(defun find-node (elt tree)
  (cond ((null tree) nil)
        ((equal (car tree) elt) tree)
        ((consp (car tree)) (let ((node (find-node elt (car tree))))
                              (if node node (find-node elt (cdr tree)))))
        (t (find-node elt (cdr tree)))))

(defun insert-before (node elt)
  (setcdr node (cons (car node) (cdr node)))
  (setcar node elt))

(let* ((function (copy-tree (symbol-function 'foo)))
       (node (find-node '(+ x y) function)))
  (when node
    (insert-before node '(if (< x 2) (setq x (* x 2))))
    (fset 'newfoo function)))

这篇关于修改功能;保存到Lisp中的新功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆