Common lisp 如何将函数列表应用于单个变量?

Common lisp 如何将函数列表应用于单个变量?,common-lisp,Common Lisp,我想写一个函数/宏 (defun apply-funcs (functions value) ...) 因此,调用apply funcs list'f'g'hx将执行与hgfx等效的操作。如何实现这一点?看起来您希望将函数列表缩减为一个值 CL-USER> (defun apply-funcs (functions value) (reduce (lambda (memo fn) (funcall fn memo)) funct

我想写一个函数/宏

(defun apply-funcs (functions value) ...)
因此,调用apply funcs list'f'g'hx将执行与hgfx等效的操作。如何实现这一点?

看起来您希望将函数列表缩减为一个值

CL-USER> (defun apply-funcs (functions value)
           (reduce (lambda (memo fn) (funcall fn memo))
                   functions :initial-value value))
CL-USER> (apply-funcs 
            (list (lambda (n) (+ 3 n))
                  (lambda (n) (- n 2))
                  (lambda (n) (* 2 n)))
            6)
14
CL-USER> 
你可能知道reduce是其他语言中的fold。我使用funcall而不是apply,因为您已经说过要在上面使用funcs列表'f'g'hx=>hgfx。如果x是一个值列表,则使用apply,每个元素都要绑定到一个单独的参数。例如,如果你想做像

(apply-funcs 
 (list (lambda (a b c)
         (list (+ a c) (+ b c)))
       (lambda (d e)
         (+ d e)))
 (list 1 2 3))
然后在apply funcs的定义中需要apply而不是funcall

根据情况,您也可以选择宏路径

(defmacro ->> (value &body functions)
  (reduce 
   (lambda (memo fn) `(funcall ,fn ,memo))
   functions :initial-value value))
这基本上是一样的

CL-USER> (->> 6
           (lambda (n) (+ 3 n))
           (lambda (n) (- n 2))
           (lambda (n) (* 2 n)))

14
CL-USER> (macroexpand
      '(->> 6
        (lambda (n) (+ 3 n))
        (lambda (n) (- n 2))
        (lambda (n) (* 2 n))))

(FUNCALL (LAMBDA (N) (* 2 N))
         (FUNCALL (LAMBDA (N) (- N 2)) 
                  (FUNCALL (LAMBDA (N) (+ 3 N)) 6)))
T
看起来您希望将函数列表缩减为一个值

CL-USER> (defun apply-funcs (functions value)
           (reduce (lambda (memo fn) (funcall fn memo))
                   functions :initial-value value))
CL-USER> (apply-funcs 
            (list (lambda (n) (+ 3 n))
                  (lambda (n) (- n 2))
                  (lambda (n) (* 2 n)))
            6)
14
CL-USER> 
你可能知道reduce是其他语言中的fold。我使用funcall而不是apply,因为您已经说过要在上面使用funcs列表'f'g'hx=>hgfx。如果x是一个值列表,则使用apply,每个元素都要绑定到一个单独的参数。例如,如果你想做像

(apply-funcs 
 (list (lambda (a b c)
         (list (+ a c) (+ b c)))
       (lambda (d e)
         (+ d e)))
 (list 1 2 3))
然后在apply funcs的定义中需要apply而不是funcall

根据情况,您也可以选择宏路径

(defmacro ->> (value &body functions)
  (reduce 
   (lambda (memo fn) `(funcall ,fn ,memo))
   functions :initial-value value))
这基本上是一样的

CL-USER> (->> 6
           (lambda (n) (+ 3 n))
           (lambda (n) (- n 2))
           (lambda (n) (* 2 n)))

14
CL-USER> (macroexpand
      '(->> 6
        (lambda (n) (+ 3 n))
        (lambda (n) (- n 2))
        (lambda (n) (* 2 n))))

(FUNCALL (LAMBDA (N) (* 2 N))
         (FUNCALL (LAMBDA (N) (- N 2)) 
                  (FUNCALL (LAMBDA (N) (+ 3 N)) 6)))
T

来自Alexandria库的compose和multiple value compose函数,包括用于compose的编译器宏。你所描述的似乎与

(funcall (alexandria:compose #'h #'g #'f) x)
以致

(defun apply-funcs (functions value)
   (funcall (apply #'compose (reverse functions)) value))
会做你想做的-尽管我怀疑直接调用compose可能更有效,这取决于上下文

图书馆的职能包括:

(defun compose (function &rest more-functions)
  "Returns a function composed of FUNCTION and MORE-FUNCTIONS that applies its
arguments to to each in turn, starting from the rightmost of MORE-FUNCTIONS,
and then calling the next one with the primary value of the last."
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (reduce (lambda (f g)
        (let ((f (ensure-function f))
          (g (ensure-function g)))
          (lambda (&rest arguments)
        (declare (dynamic-extent arguments))
        (funcall f (apply g arguments)))))
          more-functions
          :initial-value function))

(define-compiler-macro compose (function &rest more-functions)
  (labels ((compose-1 (funs)
             (if (cdr funs)
                 `(funcall ,(car funs) ,(compose-1 (cdr funs)))
                 `(apply ,(car funs) arguments))))
    (let* ((args (cons function more-functions))
           (funs (make-gensym-list (length args) "COMPOSE")))
      `(let ,(loop for f in funs for arg in args
           collect `(,f (ensure-function ,arg)))
         (declare (optimize (speed 3) (safety 1) (debug 1)))
         (lambda (&rest arguments)
           (declare (dynamic-extent arguments))
           ,(compose-1 funs))))))

来自Alexandria库的compose和multiple value compose函数,包括用于compose的编译器宏。你所描述的似乎与

(funcall (alexandria:compose #'h #'g #'f) x)
以致

(defun apply-funcs (functions value)
   (funcall (apply #'compose (reverse functions)) value))
会做你想做的-尽管我怀疑直接调用compose可能更有效,这取决于上下文

图书馆的职能包括:

(defun compose (function &rest more-functions)
  "Returns a function composed of FUNCTION and MORE-FUNCTIONS that applies its
arguments to to each in turn, starting from the rightmost of MORE-FUNCTIONS,
and then calling the next one with the primary value of the last."
  (declare (optimize (speed 3) (safety 1) (debug 1)))
  (reduce (lambda (f g)
        (let ((f (ensure-function f))
          (g (ensure-function g)))
          (lambda (&rest arguments)
        (declare (dynamic-extent arguments))
        (funcall f (apply g arguments)))))
          more-functions
          :initial-value function))

(define-compiler-macro compose (function &rest more-functions)
  (labels ((compose-1 (funs)
             (if (cdr funs)
                 `(funcall ,(car funs) ,(compose-1 (cdr funs)))
                 `(apply ,(car funs) arguments))))
    (let* ((args (cons function more-functions))
           (funs (make-gensym-list (length args) "COMPOSE")))
      `(let ,(loop for f in funs for arg in args
           collect `(,f (ensure-function ,arg)))
         (declare (optimize (speed 3) (safety 1) (debug 1)))
         (lambda (&rest arguments)
           (declare (dynamic-extent arguments))
           ,(compose-1 funs))))))

您可以通过指定:from end t:defun apply functions value reduce“funcall reverse functions:from end t:initial value”来避免显式创建包装lambda。@那么您就不需要反转函数了,对吗?这不就是reduce'funcall函数吗:从t端开始:初始值?@JoshuaTaylor:我理解首先应用第一个函数的问题。@Svante是的,你是对的。我误解了这个问题。找出哪一个代价更高是很有趣的:一个匿名函数lambda arg f funcall f arg或颠倒列表。当然,这取决于列表的大小。您可以通过指定:from end t:defun apply functions value reduce“funcall reverse functions:from end t:initial value”来避免显式创建包装lambda。@那么,您就不需要反转函数了,对吗?这不就是reduce'funcall函数吗:从t端开始:初始值?@JoshuaTaylor:我理解首先应用第一个函数的问题。@Svante是的,你是对的。我误解了这个问题。找出哪一个代价更高是很有趣的:一个匿名函数lambda arg f funcall f arg或颠倒列表。当然,这取决于名单的大小。