我有一个函数列表,一个元素列表,我想在所有元素上应用所有函数,然后将所有结果列表附加在一起。我按照以下方式做到了
(defun apply-functions(funcs elements)
(if (null funcs)
nil
(append (mapcar #'(lambda (x) (funcall (car funcs) x)) elements) (apply-functions (rest funcs) elements))))
它按预期工作,但我不喜欢它。这样做有更干净,更简洁的方法吗?我是lisp的新手,并且仍然习惯于懒散的做事方式。
答案 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)