Map (higher-order function)
In many programming languages, map is the name of a higher-order function that applies a given function to each element of a functor, e.g. a list, returning a list of results in the same order. It is often called apply-to-all when considered in functional form.
The concept of a map is not limited to lists: it works for sequential containers, tree-like containers, or even abstract containers such as futures and promises.
Examples: mapping a list
Suppose we have a list of integers
and would like to calculate the square of each integer. To do this, we first define a function to square
a single number :square x = x * x
Afterwards we may call
>>> map square
which yields
, demonstrating that map
has gone through the entire list and applied the function square
to each element.Visual example
Below, you can see a view of each step of the mapping process for a list of integersX =
that we want to map into a new list X'
according to the function :The
map
is provided as part of the Haskell's base prelude and is implemented as:map :: -> ->
map _ =
map f = f x : map f xs
Generalization
In Haskell, the polymorphic functionmap :: -> ->
is generalized to a polytypic function fmap :: Functor f => -> f a -> f b
, which applies to any type belonging the Functor
type class.The type constructor of lists
can be defined as an instance of the Functor
type class using the map
function from the previous example:instance Functor where
fmap = map
Other examples of
Functor
instances include trees:-- a simple binary tree
data Tree a = Leaf a | Fork
instance Functor Tree where
fmap f = Leaf
fmap f = Fork
Mapping over a tree yields:
>>> fmap square ) ))
Fork ) )
For every instance of the
Functor
type class, fmap
is contractually obliged to obey the functor laws:fmap id ≡ id -- identity law
fmap ≡ fmap f. fmap g -- composition law
where
.
denotes function composition in Haskell.Among other uses, this allows defining element-wise operations for various kinds of collections.
Moreover, if and are two functors, a natural transformation is a function of polymorphic type which respects :
If the function is defined by parametric polymorphism as in the type definition above, this specification is always satisfied.
Optimizations
The mathematical basis of maps allow for a number of optimizations. The composition law ensures that both-
list
and -
map list
map
requires rebuilding an entire list from scratch. Therefore, compilers will attempt to transform the first form into the second; this type of optimization is known as map fusion and is the functional analog of loop fusion.Map functions can be and often are defined in terms of a fold such as
foldr
, which means one can do a map-fold fusion: foldr f z. map g
is equivalent to foldr z
.The implementation of map above on singly linked lists is not tail-recursive, so it may build up a lot of frames on the stack when called with a large list. Many languages alternately provide a "reverse map" function, which is equivalent to reversing a mapped list, but is tail-recursive. Here is an implementation which utilizes the fold-left function.
reverseMap f = foldl
Since reversing a singly linked list is also tail-recursive, reverse and reverse-map can be composed to perform normal map in a tail-recursive way, though it requires performing two passes over the list.
Language comparison
The map function originated in functional programming languages.The language Lisp introduced a map function called
maplist
in 1959, with slightly different versions already appearing in 1958. This is the original definition for maplist
, mapping a function over successive rest lists:
maplist = -> NIL;T -> cons;maplist;f]
The function
maplist
is still available in newer Lisps like Common Lisp, though functions like mapcar
or the more generic map
would be preferred.Squaring the elements of a list using
maplist
would be written in S-expression notation like this:')
Using the function
mapcar
, above example would be written like this:')
Today mapping functions are supported in many procedural, object-oriented, and multi-paradigm languages as well: In C++'s Standard Template Library, it is called
std::transform
, in C# 's LINQ library, it is provided as an extension method called Select
. Map is also a frequently used operation in high level languages such as ColdFusion Markup Language, Perl, Python, and Ruby; the operation is called map
in all four of these languages. A collect
alias for map
is also provided in Ruby. Common Lisp provides a family of map-like functions; the one corresponding to the behavior described here is called mapcar
. There are also languages with syntactic constructs providing the same functionality as the map function.Map is sometimes generalized to accept dyadic functions that can apply a user-supplied function to corresponding elements from two lists. Some languages use special names for this, such as map2 or zipWith. Languages using explicit variadic functions may have versions of map with variable arity to support variable-arity functions. Map with 2 or more lists encounters the issue of handling when the lists are of different lengths. Various languages differ on this. Some raise an exception. Some stop after the length of the shortest list and ignore extra items on the other lists. Some continue on to the length of the longest list, and for the lists that have already ended, pass some placeholder value to the function indicating no value.
In languages which support first-class functions,
map
may be partially applied to lift a function that works on only one value to an element-wise equivalent that works on an entire container; for example, map square
is a Haskell function which squares each element of a list.Language | Map | Map 2 lists | Map n lists | Notes | Handling lists of different lengths |
APL | func list | list1 func list2 | func/ list1 list2 list3 list4 | APL's array processing abilities make operations like map implicit | length error if list lengths not equal or 1 |
Common Lisp |
|
|
| stops after the length of the shortest list | |
C++ | std::transform | std::transform | in header begin, end, and result are iterators result is written starting at result | ||
C# | ienum.Select or | ienum1.Zip | Select is an extension methodienum is an IEnumerable Zip is introduced in.NET 4.0Similarly in all.NET languages | stops after the shortest list ends | |
CFML | obj.map | Where obj is an array or a structure. func receives as arguments each item's value, its index or key, and a reference to the original object. | |||
Clojure |
|
|
| stops after the shortest list ends | |
D | list.map!func | zip.map!func | zip.map!func | Specified to zip by StoppingPolicy: shortest, longest, or requireSameLength | |
Erlang | lists:map | lists:zipwith | zipwith3 also available | Lists must be equal length | |
Elixir | Enum.map | Enum.zip |> Enum.map | List.zip |> Enum.map | stops after the shortest list ends | |
F# | List.map func list | List.map2 func list1 list2 | Functions exist for other types | Throws exception | |
Groovy | list.collect |
|
| ||
Haskell | map func list | zipWith func list1 list2 | zipWithn func list1 list2... | n corresponds to the number of lists; predefined up to zipWith7 | stops after the shortest list ends |
Haxe | array.map | ||||
J | func list | list1 func list2 | func/ list1, list2, list3,: list4 | J's array processing abilities make operations like map implicit | length error if list lengths not equal |
Java 8+ | stream.map | ||||
JavaScript 1.6 ECMAScript 5 | List1.map | List1.map | Array#map passes 3 arguments to func: the element, the index of the element, and the array. Unused arguments can be omitted. | Stops at the end of List1, extending the shorter arrays with undefined items if needed. | |
Julia | map | map | map | ERROR: DimensionMismatch | |
Logtalk | map | map | map | Only the Closure argument must be instantiated. | Failure |
Mathematica | func /@ list | MapThread | MapThread | Lists must be same length | |
Maxima | map | map returns an expression which leading operator is the same as that of the expressions; maplist returns a list | |||
OCaml | List.map func list | List.map2 func list1 list2 | raises Invalid_argument exception | ||
PARI/GP | apply | ||||
Perl | map block list | In block or expr special variable $_ holds each value from list in turn. | Helper List::MoreUtils::each_array combines more than one list until the longest one is exhausted, filling the others with undef. | ||
PHP | array_map | array_map | array_map | The number of parameters for callable should match the number of arrays. | extends the shorter lists with NULL items |
Prolog | maplist. | maplist. | maplist. | List arguments are input, output or both. Subsumes also zipWith, unzip, all | Silent failure |
Python | map | map | map | Returns a list in Python 2 and an iterator in Python 3. | zip and map stops after the shortest list ends, whereas map and itertools.zip_longest extends the shorter lists with None items |
Ruby | enum.collect | enum1.zip | enum1.zip | enum is an Enumeration | stops at the end of the object it is called on ; if any other list is shorter, it is extended with nil items |
Rust | list1.iter.map | list1.iter.zip).map | map returns an iterator. | stops after the shorter list ends | |
S-R | lapply | mapply | mapply | Shorter lists are cycled | |
Scala | list.map |
|
| note: more than 3 not possible. | stops after the shorter list ends |
Scheme |
|
|
| lists must all have same length | |
Smalltalk | aCollection collect: aBlock | aCollection1 with: aCollection2 collect: aBlock | Fails | ||
Standard ML | map func list | ListPair.map func | For 2-argument map, func takes its arguments in a tuple | ListPair.map stops after the shortest list ends, whereas ListPair.mapEq raises UnequalLengths exception | |
Swift | sequence.map | zip.map | stops after the shortest list ends | ||
XPath 3 XQuery 3 | list ! block for-each | for-each-pair | In block the context item . holds the current value | stops after the shortest list ends |