将函数映射到elisp中的两个列表

Tyl*_*ler 13 lisp elisp

在常见的lisp中,我可以这样做:

(mapcar #'cons '(1 2 3) '(a b c))

=> ((1 . A) (2 . B) (3 . C))
Run Code Online (Sandbox Code Playgroud)

我如何在elisp中做同样的事情?当我尝试时,我收到一个错误:

(wrong-number-of-arguments mapcar 3)
Run Code Online (Sandbox Code Playgroud)

如果elisp的mapcar一次只能在一个列表上工作,那么将两个列表组合成一个列表的自动方式是什么?

Jon*_*rdy 19

你想要的mapcar*,它接受一个或多个序列(不仅仅是Common Lisp中的列表),并且对于一个序列参数就像常规一样工作mapcar.

(mapcar* #'cons '(1 2 3) '(a b c))
((1 . A) (2 . B) (3 . C))
Run Code Online (Sandbox Code Playgroud)

即使没有定义,你也可以轻松推出自己的:

(defun mapcar* (f &rest xs)
  "MAPCAR for multiple sequences"
  (if (not (memq nil xs))
    (cons (apply f (mapcar 'car xs))
      (apply 'mapcar* f (mapcar 'cdr xs)))))
Run Code Online (Sandbox Code Playgroud)

  • 由于它是 cl-macs 的一部分,您应该将其称为 `cl-mapcar` 并确保使用 `(require 'cl-lib)`。 (3认同)

Mir*_*lov 10

Emacs内置了Common Lisp库,它引入了大量Common Lisp函数和宏,但带有cl-前缀.没有理由避免使用此库.cl-mapcar是你想要的:

(cl-mapcar '+ '(1 2 3) '(10 20 30)) ; (11 22 33)
Run Code Online (Sandbox Code Playgroud)

使用dash列表操作库(请参阅安装说明),您可以使用-zip-with(记住:-zip-withcl-mapcar应用于2个列表相同):

(-zip-with '+ '(1 2 3) '(10 20 30)) ; (11 22 33)
Run Code Online (Sandbox Code Playgroud)

我不知道实现-zip-with3个参数的等价物的优雅方式.但是,你可以使用-partialdash-functional包装,附带dash(功能从dash-functional需要的Emacs 24).-partial部分应用函数,因此下面的这两个函数调用是等效的:

(-zip-with '+ '(1 2) '(10 20)) ; (11 22)
(funcall (-partial '-zip-with '+) '(1 2) '(10 20)) ; (11 22)
Run Code Online (Sandbox Code Playgroud)

然后,您可以将它与-reduce函数一起使用:

(-reduce (-partial '-zip-with '+) '((1 2 3) (10 20 30) (100 200 300))) 
; (111 222 333)
Run Code Online (Sandbox Code Playgroud)

您可以使用&rest关键字将其包装到函数中,因此此函数将接受不同数量的参数而不是列表:

(defun -map* (&rest lists)
  (-reduce (-partial 'zip-with '+) lists))
Run Code Online (Sandbox Code Playgroud)