我想创建一个函数,它返回几个其他函数的组合,这样
(funcall (compose 'f 'g) x) == (f (g x))
我觉得我在这方面非常失败。迄今为止我最好的尝试:
(defun compose (funcs)
"composes several funcitons into one"
(lambda (arg)
(if funcs
(funcall (car funcs) (funcall (compose (cdr funcs)) arg))
arg)))
但由于某种原因,以下仍然返回 0:
(funcall (compose '(
(lambda (a) (* a 3))
(lambda (a) (+ a 2))
)) 0)
有办法解决吗?
您的代码需要词法作用域的 lambda,而 Emacs Lisp 默认情况下不支持。如果您使用 Emacs 24,请将
lexical-binding
设置为 t
,您的示例将按编写的方式工作。
如果您使用的是较旧的 Emacs,则可以使用显式
lexical-let
形式创建词法范围的 lambda:
(require 'cl)
(defun compose (funcs)
"composes several funcitons into one"
(lexical-let ((funcs funcs))
(lambda (arg)
(if funcs
(funcall (car funcs) (funcall (compose (cdr funcs)) arg))
arg))))
对于那些不喜欢其他答案的人,这里有一个
compose
,其中
(defmacro compose (&rest functions)
(setq functions (nreverse functions))
(let ((form `(apply ,(car functions) arguments)))
(while (setq functions (cdr functions))
(setq form `(funcall ,(car functions) ,form)))
`(lambda (&rest arguments) ,form)))
这也说明了另一种方法:无需创建必须记住函数列表并在每次调用时遍历它的递归 lambda,而是将整个函数列表扩展为 lambda 形式一次。
例如,
(compose 'f 'g 'h)
扩展为:
(lambda (&rest arguments)
(funcall 'f (funcall 'g (apply 'h arguments))))