应用列表以在常见的lisp中列出

时间:2012-10-17 15:26:06

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

我有一个函数列表,一个元素列表,我想在所有元素上应用所有函数,然后将所有结果列表附加在一起。我按照以下方式做到了

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

它按预期工作,但我不喜欢它。这样做有更干净,更简洁的方法吗?我是lisp的新手,并且仍然习惯于懒散的做事方式。

3 个答案:

答案 0 :(得分:6)

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

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

答案 1 :(得分:5)

这与你的想法相同,只是更短:

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

答案 2 :(得分:4)

我会定义一个返回新函数的函数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)  

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

(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)