映射指的是把一个函数应用到序列的每个元素上,从而得到一个新的序列。
可以用mapcar把一个函数映射到一个对象列表上:
(mapcar #'double '(1 2 3 4)) ; => (2 4 6 8)
注意,第一个实参是要调用的函数。
#'是一种特殊的引用语法,用来指定一个函数。
(这里也可以用'double,但使用#'更符合习惯,而且可以说“更正确”。)
映射并不局限于把函数应用到一个序列上,也可以作用于多个序列。
如果提供了N个序列,那么函数必须接受N个实参。
(mapcar #'list '(1 2) '(a b) '("foo" "bar")) ; => ((1 a "foo") (2 b "bar"))
除了mapcar,还有其他用于在列表上映射的函数。
mapcar无疑是最常用的,不过了解一下其他函数也很有好处。
maplist的用法与mapcar类似,但它作用的是依次递进的子列表,而不是元素。
先是整个列表,然后是它的cdr,再然后是那个cdr的cdr,依此类推:
(maplist #'identity '(a b c)) ; => ((A B C) (B C) (C))
mapc和mapl分别类似于mapcar和maplist,但它们不收集结果,而是返回第一个列表。
这类函数用于产生副作用的操作。
mapcan和mapcon类似于mapcar和maplist,但结果会借助nconc展平。nconc类似于append,但它对除最后一个实参以外的所有实参都具有破坏性。
映射并不局限于列表。任何序列(在另一个概念中介绍)都可以被映射。
对于非列表的序列,则使用map函数。
map接受 3 个或更多实参:
(map 'list #'double '(1 2 3)) ; => (2 4 6)
(map 'string #'char-upcase "foobar") ; => "FOOBAR"
作为一种特殊情况,如果把nil作为结果序列的类型,那么返回的就是nil。
这种用法(和上面的mapc、mapl一样)是为了产生副作用。