我需要创建一个生成如下函数的函数:
(defun add3 (val) (+ 3 val))
Run Code Online (Sandbox Code Playgroud)
应该像这样使用:
(setq adder7 nil)
(fset 'adder7 (make-adder 7))
(adder7 3)
=> 10
Run Code Online (Sandbox Code Playgroud)
理想情况下,函数make-adder应该返回除了参数之外没有任何符号的lambdas,例如:
(make-adder 7)
=> (lambda (val) (+ 7 val))
Run Code Online (Sandbox Code Playgroud)
更新
我尝试过以下天真的实现:
(defun make-adder (n)
(lambda (x) (+ n x)))
Run Code Online (Sandbox Code Playgroud)
但是这会生成一个包含自由符号(不是数字常量!)的lambda,并且它的使用失败.
(defalias 'add1 (make-adder 1))
(add1 2)
=> Debugger error void-variable n
(let ((n 5))
(add1 2))
=> 7
Run Code Online (Sandbox Code Playgroud)
这根本不是我想要的.
默认情况下,Emacs依赖于动态范围.这就是n返回的lambda中的符号引用未绑定变量的原因.要么切换词法作用域,要么使用当前值构建lambda表单n,如下所示:
(defun make-adder (n)
`(lambda (x) (+ ,n x)))
Run Code Online (Sandbox Code Playgroud)
然后:
(defalias 'add1 (make-adder 1))
(add1 3)
=> 4
Run Code Online (Sandbox Code Playgroud)
我原本以为这个问题是关于Common Lisp(fset应该给我一个提示),你只需要这样做:
(defun make-adder (n)
(lambda (x) (+ n x)))
Run Code Online (Sandbox Code Playgroud)
你的函数接受一个n并返回一个匿名函数,它接受另一个参数x并产生结果.但是等等,make-adder只是将一些参数部分应用于函数的特殊情况(有关currying和部分应用之间区别的详细信息,请参阅此问题).部分应用函数的一般方法是:
(defun partial (function &rest partial-args)
(lambda (&rest args)
(apply function (append partial-args args))))
Run Code Online (Sandbox Code Playgroud)
例如:
(let ((3+ (partial #'+ 3)))
(funcall 3+ 7))
=> 10
Run Code Online (Sandbox Code Playgroud)