2

我有一个函数列表,一个元素列表,我想将所有函数应用于所有元素,然后将所有结果列表附加在一起。我做了如下

(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 的做事风格。

4

3 回答 3

6

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

(defun apply-functions (fs es)
    (loop for f in fs appending (mapcar f es)))
于 2012-10-17T15:52:12.133 回答
6

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

(defun apply-functions (functions elements)
  (mapcan #'(lambda (x) (mapcar x elements)) functions))
于 2012-10-17T18:53:04.500 回答
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)  

不幸的是nconcmapcan使用的是破坏性的:

(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)
于 2012-10-17T19:05:15.453 回答