Content deleted Content added
→Language comparison: style="font-size: 85%" |
m →Language comparison: {{code}} |
||
(60 intermediate revisions by 44 users not shown) | |||
Line 1:
<references group="pakistni" />
{{Short description|Computer programming function}}
{{for|the abstract data type of the same name|Map (data structure)}}
{{one source|date=November 2012}}
In many [[programming language]]s, '''map''' is
The concept of a map is not limited to lists: it works for sequential [[Container (abstract data type)|containers]], tree-like containers, or even abstract containers such as [[futures and promises]].
==
Suppose
<
square x = x * x
</syntaxhighlight>
Afterwards
<
>>> map square [1, 2, 3, 4, 5]
</syntaxhighlight>
which yields <code>[1, 4, 9, 16, 25]</code>, demonstrating that <code>map</code> has gone through the entire list and applied the function <code>square</code> to each element.
=== Visual example ===
Below, there is view of each step of the mapping process for a list of integers <code>X = [0, 5, 8, 3, 2, 1]</code> mapping into a new list <code>X'</code> according to the function <math>f(x) = x + 1</math> :
[[File:Mapping-steps-loillibe-new.gif|alt=applying map function processing steps|none|thumb|480x480px|View of processing steps when applying map function on a list]]
The <code>map</code> is provided as part of the Haskell's base prelude (i.e. "standard library") and is implemented as:
<syntaxhighlight lang="haskell">
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x : xs) = f x : map f xs
</syntaxhighlight>
== Generalization ==
{{see also|Functor|Category theory}}
In Haskell, the [[polymorphic function]]
The [[type constructor]] of lists <code>[]</code> can be defined as an instance of the <code>Functor</code> type class using the <code>map</code> function from the previous example:
<
instance Functor [] where
fmap = map
</syntaxhighlight>
Other examples of <code>Functor</code> instances include trees:
<
-- a simple binary tree
data Tree a = Leaf a | Fork (Tree a) (Tree a)
Line 49 ⟶ 59:
fmap f (Leaf x) = Leaf (f x)
fmap f (Fork l r) = Fork (fmap f l) (fmap f r)
</syntaxhighlight>
Mapping over a tree yields:
<
>>> fmap square (Fork (Fork (Leaf 1) (Leaf 2)) (Fork (Leaf 3) (Leaf 4)))
Fork (Fork (Leaf 1) (Leaf 4)) (Fork (Leaf 9) (Leaf 16))
</syntaxhighlight>
For every instance of the <code>Functor</code> type class, <code>fmap</code> is [[design by contract|contractually obliged]] to obey the functor laws:
<
fmap id ≡ id -- identity law
fmap (f . g) ≡ fmap f . fmap g -- composition law
</syntaxhighlight>
where <code>.</code> denotes [[function composition (computer science)|function composition]] in Haskell.
Among other uses, this allows defining element-wise operations for various kinds of [[collection (computer science)|collections]].
=== Category-theoretic background ===
In [[category theory]], a [[functor]] <math>F : C \rarr D</math> consists of two maps: one that sends each object {{mvar|A}} of the category to another object {{mvar|F A}}, and one that sends each morphism <math>f : A \rarr B</math> to another morphism <math>Ff : FA \rarr FB</math>, which acts as a [[homomorphism]] on categories (i.e. it respects the category axioms). Interpreting the universe of data types as a category {{mvar|Type}}, with morphisms being functions, then a type constructor <code>F</code> that is a member of the <code>Functor</code> type class is the object part of such a functor, and {{code|2=haskell|1=fmap :: (a -> b) -> F a -> F b}} is the morphism part. The functor laws described above are precisely the category-theoretic functor axioms for this functor.
Functors can also be objects in categories, with "morphisms" called [[natural transformation]]s. Given two functors <math>F, G : C \rarr D</math>, a natural transformation <math>\eta : F \rarr G</math> consists of a collection of morphisms <math>\eta_A : FA \rarr GA</math>, one for each object {{mvar|A}} of the category {{mvar|D}}, which are 'natural' in the sense that they act as a 'conversion' between the two functors, taking no account of the objects that the functors are applied to. Natural transformations correspond to functions of the form {{code|2=haskell|1=eta :: F a -> G a}}, where <code>a</code> is a universally quantified type variable – <code>eta</code> knows nothing about the type which inhabits <code>a</code>. The naturality axiom of such functions is automatically satisfied because it is a so-called free theorem, depending on the fact that it is [[parametric polymorphism|parametrically polymorphic]].<ref>In a [[non-strict language]] that permits general recursion, such as Haskell, this is only true if the first argument to <code>fmap</code> is strict. {{cite conference |title=Theorems for free! |first=Philip |last=Wadler |author-link=Philip Wadler |conference=4th International Symposium on Functional Programming Languages and Computer Architecture |___location=London |date=September 1989 |url=https://people.mpi-sws.org/~dreyer/tor/papers/wadler.pdf |publisher=[[Association for Computing Machinery]]}}</ref> For example, {{code|2=haskell|1=reverse :: List a -> List a}}, which reverses a list, is a natural transformation, as is {{code|2=haskell|1=flattenInorder :: Tree a -> List a}}, which flattens a tree from left to right, and even {{code|2=haskell|1=sortBy :: (a -> a -> Bool) -> List a -> List a}}, which sorts a list based on a provided comparison function.
==Optimizations==
Line 83 ⟶ 94:
The implementation of map above on singly linked lists is not [[tail recursion|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 (higher-order function)|fold]]-left function.
<
reverseMap f = foldl (\ys x -> f x : ys) []
</syntaxhighlight>
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==
Line 93 ⟶ 104:
The map function originated in [[functional programming]] languages.
The language [[Lisp (programming language)|Lisp
<
maplist[x;f] = [null[x] -> NIL;T -> cons[f[x];maplist[cdr[x];f]]]
</
The function <code>maplist</code> is still available in newer Lisps like [[Common Lisp]],<ref>[http://www.lispworks.com/documentation/HyperSpec/Body/f_mapc_.htm Function MAPC, MAPCAR, MAPCAN, MAPL, MAPLIST, MAPCON in ANSI Common Lisp]</ref> though functions like <code>mapcar</code> or the more generic <code>map</code> would be preferred.
Squaring the elements of a list using <code>maplist</code> would be written in
<
(maplist (
</syntaxhighlight>
Using the function <code>mapcar</code>, above example would be written like this:
<
(mapcar (function sqr) '(1 2 3 4 5))
</syntaxhighlight>
Today mapping functions are supported (or may be defined) in many [[procedural programming|procedural]], [[
Map is sometimes generalized to accept dyadic (2-argument) functions that can apply a user-supplied function to corresponding elements from two lists
In languages which support [[first-class function]]s and [[currying]], <code>map</code> may be [[partial application|partially applied]] to ''lift'' a function that
{| class="wikitable" style="font-size: 85%"
|+ Map in various languages
! scope="col" | Language
! scope="col" | Map
! scope="col" | Map 2 lists
! scope="col" | Map n lists
! scope="col" | Notes
! scope="col" | Handling lists of different lengths
|- valign="top"
| [[APL (programming language)|APL]]
| <code>''func'' ''list''</code>
| <code>''list1'' ''func'' ''list2''</code>
| <code>''func''/ ''list1'' ''list2'' ''list3'' ''list4''</code>
| APL's array processing abilities make operations like map implicit
| length error if list lengths not equal or 1
|- valign="top"
| [[Common Lisp]]
Line 136 ⟶ 157:
| <code>std::transform(<wbr/>''begin1'', ''end1'', ''begin2'', ''result'', ''func'')</code>
|
| in header {{mono|<algorithm>}}<br /> ''begin'', ''end'', and ''result'' are iterators<br /> result is written starting at ''result''
|
|- valign="top"
| [[C Sharp (programming language)|C#]]
| <code>''ienum''.Select(''func'')</code><br />or<br />[https://msdn.microsoft.com/en-us/library/bb384087.aspx The <code>select</code> clause]
| <code>''ienum1''.Zip(''ienum2'', ''func'')</code>
|
Line 187 ⟶ 208:
| Functions exist for other types (''Seq'' and ''Array'')
| Throws exception
|- valign="top"
| [[Gleam (programming language)|Gleam]]
| <code>list.map(''list'', ''func'')</code><br><code>yielder.map(''yielder'', ''func'')</code>
| <code>list.map2(''list1'', ''list2'', ''func'')</code><br><code>yielder.map2(''yielder1'', ''yielder2'', ''func'')</code>
|
|
| drops the extra elements of the longer list
|- valign="top"
| [[Groovy (programming language)|Groovy]]
| {{code|list.collect(func)|groovy}}
| {{code|[list1 list2].transpose().collect(func)|groovy}}
| {{code|[list1 list2 ...].transpose().collect(func)|groovy}}
|
|
|- valign="top"
| [[Haskell (programming language)|Haskell]]
Line 194 ⟶ 229:
| <code>''n''</code> corresponds to the number of lists; predefined up to <code>''zipWith7''</code>
| stops after the shortest list ends
|- valign="top"
| [[Haxe]]
| <code>''array''.map(''func'')<br />''list''.map(''func'')<br />Lambda.map(''iterable'', ''func'')</code>
|
|
Line 216 ⟶ 241:
| <code>''list1'' ''func'' ''list2''</code>
| <code>''func''/ ''list1'', ''list2'', ''list3'' ,: ''list4''</code>
| J's array processing
| length error if list lengths not equal
|- valign="top"
Line 226 ⟶ 251:
|
|- valign="top"
| [[JavaScript]] 1.6<br />[[ECMAScript]] 5
| [https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map <code>''array''#map(''func'')</code>]
| <code>''List1''.map(function (elem1, i) { <br />return ''func''(elem1, ''List2''[i]); })</code>
Line 232 ⟶ 257:
| 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.
|- valign="top"
| [[Julia (programming language)|Julia]]
| <code>map(''func'', ''list'')</code>
| <code>map(''func'', ''list1, list2'')</code>
| <code>map(''func'', ''list1, list2, ..., listN'')</code>
|
| ERROR: DimensionMismatch
|- valign="top"
| [[Logtalk]]
Line 251 ⟶ 285:
|
|
| map returns an expression
|
|- valign="top"
Line 302 ⟶ 336:
| <code>''enum'' is an Enumeration</code>
| stops at the end of the object it is called on (the first list); if any other list is shorter, it is extended with ''nil'' items
|-
|[[Rust (programming language)|Rust]]
| <code>''list1''.into_iter().map(''func'')</code>
| <code>''list1''.into_iter().zip(''list2'').map(''func'')</code>
|
| the <code>Iterator::map</code> and <code>Iterator::zip</code> methods both take ownership of the original iterator and return a new one; the <code>Iterator::zip</code> method internally calls the <code>IntoIterator::into_iter</code> method on <code>''list2''</code>
| stops after the shorter list ends
|- valign="top"
| [[S (programming language)|S]]
| <code>lapply(''list'', ''func'')</code>
| <code>mapply(''func'', ''list1'', ''list2'')</code>
Line 317 ⟶ 358:
| stops after the shorter list ends
|- valign="top"
| [[Scheme (programming language)|Scheme]]
| <code>(map ''func'' ''list'')</code>
| <code>(map ''func'' ''list1'' ''list2'')</code>
| <code>(map ''func'' ''list1'' ''list2'' ...)</code>
|
| lists must all have same length (SRFI-1 extends to take lists of different length)
|- valign="top"
| [[Smalltalk]]
Line 338 ⟶ 379:
| <code>''ListPair.map''</code> stops after the shortest list ends, whereas <code>''ListPair.mapEq''</code> raises <code>UnequalLengths</code> exception
|- valign="top"
| [[Swift (
| <code>''
| <code>
|
|
| stops after the shortest list ends
|- valign="top"
| [[XPath 3
|
|
|
| In <code>block</code> the context item <code>.</code> holds the current value
Line 354 ⟶ 395:
==See also==
* [[Functor (functional programming)]]
* [[
* [[Filter (higher-order function)]]
* [[Fold (higher-order function)]]
* [[foreach loop]]
* [[Free monoid]]
* [[Functional programming]]
Line 366 ⟶ 407:
==References==
{{Reflist}}
[[Category:Higher-order functions]]
|