Movatterモバイル変換


[0]ホーム

URL:


Jump to content
WikipediaThe Free Encyclopedia
Search

Map (higher-order function)

From Wikipedia, the free encyclopedia
Computer programming function
For the abstract data type of the same name, seeMap (data structure).
This articlerelies largely or entirely on asingle source. Relevant discussion may be found on thetalk page. Please helpimprove this article byintroducing citations to additional sources.
Find sources: "Map" higher-order function – news ·newspapers ·books ·scholar ·JSTOR
(November 2012)
Comparison of
programming languages

In manyprogramming languages,map is ahigher-order function that applies agiven function to each element of acollection, e.g. alist orset, returning the results in a collection of the same type. It is often calledapply-to-all when considered infunctional form.

The concept of a map is not limited to lists: it works for sequentialcontainers, tree-like containers, or even abstract containers such asfutures and promises.

Examples: mapping a list

[edit]

Suppose there is a list of integers[1, 2, 3, 4, 5] . To calculate thesquare of each integer, one would first define a function tosquare a single number (shown here inHaskell):

squarex=x*x

Afterwards, call:

>>>mapsquare[1,2,3,4,5]

which yields[1, 4, 9, 16, 25], demonstrating thatmap has gone through the entire list and applied the functionsquare to each element.

Visual example

[edit]

Below, is a view of each step of the mapping process for a list of integersX = [0, 5, 8, 3, 2, 1] mapping into a new listX' according to the functionf(x)=x+1{\displaystyle f(x)=x+1} :

applying map function processing steps
View of processing steps when applying map function on a list

Themap is provided as part of the Haskell's base prelude (i.e. "standard library") and is implemented as:

map::(a->b)->[a]->[b]map_[]=[]mapf(x:xs)=fx:mapfxs

Generalization

[edit]
See also:Functor andCategory theory

In Haskell, thepolymorphic functionmap::(a->b)->[a]->[b] is generalized to apolytypic functionfmap::Functorf=>(a->b)->fa->fb, which applies to any type belonging theFunctortype class.

Thetype constructor of lists[] can be defined as an instance of theFunctor type class using themap function from the previous example:

instanceFunctor[]wherefmap=map

Other examples ofFunctor instances include trees:

-- a simple binary treedataTreea=Leafa|Fork(Treea)(Treea)instanceFunctorTreewherefmapf(Leafx)=Leaf(fx)fmapf(Forklr)=Fork(fmapfl)(fmapfr)

Mapping over a tree yields:

>>>fmapsquare(Fork(Fork(Leaf1)(Leaf2))(Fork(Leaf3)(Leaf4)))Fork(Fork(Leaf1)(Leaf4))(Fork(Leaf9)(Leaf16))

For every instance of theFunctor type class,fmap iscontractually obliged to obey the functor laws:

fmapidid-- identity lawfmap(f.g)fmapf.fmapg-- composition law

where. denotesfunction composition in Haskell.

Among other uses, this allows defining element-wise operations for various kinds ofcollections.

Category-theoretic background

[edit]

Incategory theory, afunctorF:CD{\displaystyle F:C\rightarrow D} consists of two maps: one that sends each objectA of the category to another objectF A, and one that sends each morphismf:AB{\displaystyle f:A\rightarrow B} to another morphismFf:FAFB{\displaystyle Ff:FA\rightarrow FB}, which acts as ahomomorphism on categories (i.e. it respects the category axioms). Interpreting the universe of data types as a categoryType, with morphisms being functions, then a type constructorF that is a member of theFunctor type class is the object part of such a functor, andfmap::(a->b)->Fa->Fb 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" callednatural transformations. Given two functorsF,G:CD{\displaystyle F,G:C\rightarrow D}, a natural transformationη:FG{\displaystyle \eta :F\rightarrow G} consists of a collection of morphismsηA:FAGA{\displaystyle \eta _{A}:FA\rightarrow GA}, one for each objectA of the categoryD, 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 formeta::Fa->Ga, wherea is a universally quantified type variable –eta knows nothing about the type which inhabitsa. The naturality axiom of such functions is automatically satisfied because it is a so-called free theorem, depending on the fact that it isparametrically polymorphic.[1] For example,reverse::Lista->Lista, which reverses a list, is a natural transformation, as isflattenInorder::Treea->Lista, which flattens a tree from left to right, and evensortBy::(a->a->Bool)->Lista->Lista, which sorts a list based on a provided comparison function.

Optimizations

[edit]

The mathematical basis of maps allow for a number ofoptimizations. The composition law ensures that both

  • (map f . map g) list and
  • map (f . g) list

lead to the same result; that is,map(f)map(g)=map(fg){\displaystyle \operatorname {map} (f)\circ \operatorname {map} (g)=\operatorname {map} (f\circ g)}. However, the second form is more efficient to compute than the first form, because eachmap 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 asmap fusion and is thefunctional analog ofloop fusion.[2]

Map functions can be and often are defined in terms of afold such asfoldr, which means one can do amap-fold fusion:foldr f z . map g is equivalent tofoldr (f . g) z.

The implementation of map above on singly linked lists is nottail-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 thefold-left function.

reverseMapf=foldl(\ysx->fx:ys)[]

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

[edit]

The map function originated infunctional programming languages.

The languageLisp introduced a map function calledmaplist[3] in 1959, with slightly different versions already appearing in 1958.[4] This is the original definition formaplist, mapping a function over successive rest lists:

maplist[x;f] = [null[x] -> NIL;T -> cons[f[x];maplist[cdr[x];f]]]

The functionmaplist is still available in newer Lisps likeCommon Lisp,[5] though functions likemapcar or the more genericmap would be preferred.

Squaring the elements of a list usingmaplist would be written inS-expression notation like this:

(maplist(lambda(l)(sqr(carl)))'(12345))

Using the functionmapcar, above example would be written like this:

(mapcar(functionsqr)'(12345))

Today mapping functions are supported (or may be defined) in manyprocedural,object-oriented, andmulti-paradigm languages as well: InC++'sStandard Library, it is calledstd::transform orstd::ranges::transform, inC# (3.0)'s LINQ library, it is provided as an extension method calledSelect. Map is also a frequently used operation in high level languages such asColdFusion Markup Language (CFML),Perl,Python, andRuby; the operation is calledmap in all four of these languages. Acollect alias formap is also provided in Ruby (fromSmalltalk).Common Lisp provides a family of map-like functions; the one corresponding to the behavior described here is calledmapcar (-car indicating access using theCAR operation). There are also languages with syntactic constructs providing the same functionality as the map function.

Map is sometimes generalized to accept dyadic (2-argument) functions that can apply a user-supplied function to corresponding elements from two lists. Some languages use special names for this, such asmap2 orzipWith. Languages using explicitvariadic functions may have versions of map with variablearity to supportvariable-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 supportfirst-class functions andcurrying,map may bepartially applied tolift 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.

Map in various languages
LanguageMapMap 2 listsMap n listsNotesHandling lists of different lengths
APLfunclistlist1funclist2func/list1list2list3list4APL's array processing abilities make operations like map implicitlength error if list lengths not equal or 1
Common Lisp(mapcarfunclist)(mapcarfunclist1list2)(mapcarfunclist1list2 ...)stops after the length of the shortest list
C++std::transform(begin,end,result,func)
list | std::views::transform(result,func)
std::transform(begin1,end1,begin2,result,func)
std::views::zip_transform(func,list1,list2)
std::views::zip_transform(func,list1,list2 ...)in header<algorithm>
begin,end, andresult are iterators
result is written starting atresult
C#ienum.Select(func)
or
Theselect clause
ienum1.Zip(ienum2,func)Select is an extension method
ienum is an IEnumerable
Zip is introduced in .NET 4.0
Similarly in all .NET languages
stops after the shortest list ends
CFMLobj.map(func)Whereobj 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(mapfunclist)(mapfunclist1list2)(mapfunclist1list2 ...)stops after the shortest list ends
Dlist.map!funczip(list1,list2).map!funczip(list1,list2, ...).map!funcSpecified to zip by StoppingPolicy: shortest, longest, or requireSameLength
Erlanglists:map(Fun,List)lists:zipwith(Fun,List1,List2)zipwith3 also availableLists must be equal length
ElixirEnum.map(list,fun)Enum.zip(list1,list2) |> Enum.map(fun)List.zip([list1,list2, ...]) |> Enum.map(fun)stops after the shortest list ends
F#List.mapfunclistList.map2funclist1list2Functions exist for other types (Seq andArray)Throws exception
Gleamlist.map(list,func)
yielder.map(yielder,func)
list.map2(list1,list2,func)
yielder.map2(yielder1,yielder2,func)
drops the extra elements of the longer list
Groovylist.collect(func)[list1list2].transpose().collect(func)[list1list2...].transpose().collect(func)
HaskellmapfunclistzipWithfunclist1list2zipWithnfunclist1list2 ...n corresponds to the number of lists; predefined up tozipWith7stops after the shortest list ends
Haxearray.map(func)
list.map(func)
Lambda.map(iterable,func)
Jfunclistlist1funclist2func/list1,list2,list3 ,:list4J's array processing abilities make operations like map implicitlength error if list lengths not equal
Java 8+stream.map(func)
JavaScript 1.6
ECMAScript 5
array#map(func)List1.map(function(elem1,i){returnfunc(elem1,List2[i]); })List1.map(function(elem1,i){returnfunc(elem1,List2[i],List3[i], ...); })Array#map passes 3 arguments tofunc: the element, the index of the element, and the array. Unused arguments can be omitted.Stops at the end ofList1, extending the shorter arrays withundefined items if needed.
Juliamap(func,list)map(func,list1, list2)map(func,list1, list2, ..., listN)ERROR: DimensionMismatch
Logtalkmap(Closure,List)map(Closure,List1,List2)map(Closure,List1,List2,List3, ...) (up to seven lists)Only theClosure argument must be instantiated.Failure
Mathematicafunc /@list
Map[func,list]
MapThread[func, {list1,list2}]MapThread[func, {list1,list2, ...}]Lists must be same length
Maximamap(f,expr1, ...,exprn)
maplist(f,expr1, ...,exprn)
map returns an expression which leading operator is the same as that of the expressions;
maplist returns a list
OCamlList.mapfunclist
Array.mapfuncarray
List.map2funclist1list2raises Invalid_argument exception
PARI/GPapply(func,list)
Perlmapblocklist
mapexpr,list
Inblock orexpr special variable$_ holds each value from list in turn.HelperList::MoreUtils::each_array combines more than one list until the longest one is exhausted, filling the others withundef.
PHParray_map(callable,array)array_map(callable,array1,array2)array_map(callable,array1,array2, ...)The number of parameters forcallable
should match the number of arrays.
extends the shorter lists withNULL items
Prologmaplist(Cont,List1,List2).maplist(Cont,List1,List2,List3).maplist(Cont,List1,...).List arguments are input, output or both. Subsumes also zipWith, unzip, allSilent failure (not an error)
Pythonmap(func,list)map(func,list1,list2)map(func,list1,list2, ...)Returns a list in Python 2 and aniterator in Python 3.zip() andmap() (3.x) stops after the shortest list ends, whereasmap() (2.x) anditertools.zip_longest() (3.x) extends the shorter lists withNone items
Rubyenum.collect {block}
enum.map {block}
enum1.zip(enum2).map {block}enum1.zip(enum2, ...).map {block}
[enum1,enum2, ...].transpose.map {block}
enum is an Enumerationstops at the end of the object it is called on (the first list); if any other list is shorter, it is extended withnil items
Rustlist1.into_iter().map(func)list1.into_iter().zip(list2).map(func)theIterator::map andIterator::zip methods both take ownership of the original iterator and return a new one; theIterator::zip method internally calls theIntoIterator::into_iter method onlist2stops after the shorter list ends
S-Rlapply(list,func)mapply(func,list1,list2)mapply(func,list1,list2, ...)Shorter lists are cycled
Scalalist.map(func)(list1,list2).zipped.map(func)(list1,list2,list3).zipped.map(func)note: more than 3 not possible.stops after the shorter list ends
Scheme (includingGuile andRacket)(mapfunclist)(mapfunclist1list2)(mapfunclist1list2 ...)lists must all have same length (SRFI-1 extends to take lists of different length)
SmalltalkaCollection collect:aBlockaCollection1 with:aCollection2 collect:aBlockFails
Standard MLmapfunclistListPair.mapfunc (list1,list2)
ListPair.mapEqfunc (list1,list2)
For 2-argument map,func takes its arguments in a tupleListPair.map stops after the shortest list ends, whereasListPair.mapEq raisesUnequalLengths exception
Swiftsequence.map(func)zip(sequence1,sequence2).map(func)stops after the shortest list ends
XPath 3
XQuery 3
list!block
for-each(list,func)
for-each-pair(list1,list2,func)Inblock the context item. holds the current valuestops after the shortest list ends

See also

[edit]

References

[edit]
  1. ^In anon-strict language that permits general recursion, such as Haskell, this is only true if the first argument tofmap is strict.Wadler, Philip (September 1989).Theorems for free!(PDF). 4th International Symposium on Functional Programming Languages and Computer Architecture. London:Association for Computing Machinery.
  2. ^"Map fusion: Making Haskell 225% faster"
  3. ^J. McCarthy, K. Maling, S. Russell, N. Rochester, S. Goldberg, J. Slagle. LISP Programmer's Manual. March-April, 1959
  4. ^J. McCarthy: Symbol Manipulating Language - Revisions of the Language. AI Memo No. 4, October 1958
  5. ^Function MAPC, MAPCAR, MAPCAN, MAPL, MAPLIST, MAPCON in ANSI Common Lisp
Retrieved from "https://en.wikipedia.org/w/index.php?title=Map_(higher-order_function)&oldid=1322501543"
Categories:
Hidden categories:

[8]ページ先頭

©2009-2025 Movatter.jp