【问题标题】:applying list of functions to list in common lisp将函数列表应用于 common lisp 中的列表
【发布时间】:2012-10-17 15:26:05
【问题描述】:

我有一个函数列表,一个元素列表,我想将所有函数应用于所有元素,然后将所有结果列表附加在一起。我是按照下面的方法做的

(defun apply-functions(funcs elements)
    (if (null funcs)
        nil
        (append (mapcar #'(lambda (x) (funcall (car funcs) x)) elements) (apply-functions (rest funcs) elements))))

它按预期工作,但我不喜欢它。有没有更干净,更简洁的方法?我是 lisp 新手,仍然习惯于 lispish 的做事风格。

【问题讨论】:

    标签: list common-lisp higher-order-functions


    【解决方案1】:

    我不知道你是否喜欢loop 宏(我不想破坏任何人),但试试这个:

    (defun apply-functions (fs es)
        (loop for f in fs appending (mapcar f es)))
    

    【讨论】:

    • 之前没用过loop,不过看起来不错。我会读到的。非常感谢。
    【解决方案2】:

    这和你的想法一样,只是更短:

    (defun apply-functions (functions elements)
      (mapcan #'(lambda (x) (mapcar x elements)) functions))
    

    【讨论】:

    • 这很好,(汽车 x)在这里不是必需的,对吧?..它不应该只是 mapcar x 元素吗?
    • 用mapcan代替mapcon怎么样?那应该摆脱 (car x),而只需要 x。
    • 这个版本很不错。这比循环版本更有效吗?
    【解决方案3】:

    我会定义一个函数,call-each,它返回一个新函数, 返回在其参数上调用每个函数的列表:

    (defun call-each (fns)
      (lambda (arg)
        (mapcar (lambda (fn)
                  (funcall fn arg))
                fns)))
    
    (funcall (call-each (list #'third #'second #'first)) '(a b c))
    ;=> (C B A)
    

    cl 有函数mapcan 基本上是nconc + mapcar

    (mapcan #'reverse '((a b c)
                        (e f g)
                        (h i j)))
    ;=> (C B A G F E J I H)
    
    (mapcan (call-each (list #'identity #'1+)) '(1 3 5 7 9))
    ;=> (1 2 3 4 5 6 7 8 9 10)  
    

    不幸的是,mapcan 使用的 nconc 具有破坏性:

    (let ((data '((a b c)
                  (d e f)
                  (g h i))))
      ;;here be dragons
      (list (mapcan #'identity data)
            data))
    ;=> ((A B C D E F G H I) ((A B C D E F G H I) (D E F G H I) (G H I)))
    

    alexandria 救援:

    (let ((data '((a b c)
                  (d e f)
                  (g h i))))
      ;;safe version
      (list (alexandria:mappend #'identity data)
            data))
    ;=> ((A B C D E F G H I) ((A B C) (D E F) (G H I)))
    

    请注意,使用mapcan 效率更高,但除非您确切知道在哪里 你的数据来自哪里,谁拥有它,mappend 是要走的路。

    所以你可以写:

    (defun apply-functions (fs es)
      (when fs
        (alexandria:mappend (call-each fs) es))
    
    (apply-functions (list #'identity #'1+) '(1 3 5 7 9))
    ;=> (1 2 3 4 5 6 7 8 9 10)
    

    【讨论】:

      猜你喜欢
      • 2016-12-13
      • 2014-11-28
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多