Térkép (magasabb rendű funkció) - Map (higher-order function)

Sok programozási nyelvek , térkép a neve egy magasabb rendű függvény , amely érvényes a megadott függvény , hogy minden egyes eleme egy funktorhoz , például egy lista , visszatérve a találati listát ugyanabban a sorrendben. Gyakran alkalmazható mindennek, ha funkcionális formában tekintik .

A térkép fogalma nem korlátozódik a listákra: szekvenciális konténerekre , faszerű konténerekre, vagy akár absztrakt konténerekre, például határidős és ígéretes konténerekre vonatkozik .

Példák: lista feltérképezése

Tegyük fel, hogy van egy egész számok listája, [1, 2, 3, 4, 5]és ki szeretnénk számítani az egyes egészek négyzetét. Ehhez először definiálunk egy függvényt squareegyetlen számhoz (itt látható a Haskellben ):

square x = x * x

Utána hívhatunk

>>> map square [1, 2, 3, 4, 5]

amely azt eredményezi [1, 4, 9, 16, 25], hogy mapa teljes listán keresztülment, és squareminden elemre alkalmazta a függvényt .

Vizuális példa

Az alábbiakban megtekintheti a leképezési folyamat egyes lépéseinek nézetét azoknak az egész számoknak X = [0, 5, 8, 3, 2, 1]a listájához X', amelyeket a funkciónak megfelelően új listába szeretnénk leképezni  :

térképfüggvény -feldolgozási lépések alkalmazása
A feldolgozási lépések nézete a térképfunkció listán való alkalmazásakor

A mapHaskell alap -előjátéka (azaz "standard könyvtár") része, és a következőképpen valósul meg:

map :: (a -> b) -> [a] -> [b]
map _ []       = []
map f (x : xs) = f x : map f xs

Általánosítás

Haskell -ben a polimorf függvényt map :: (a -> b) -> [a] -> [b] egy poltipikus függvényre általánosítják fmap :: Functor f => (a -> b) -> f a -> f b, amely minden típusosztályhoz tartozó típusra vonatkozik . Functor

A típusú kivitelező listák []lehet meghatározni, mint egy példány a Functortípusú osztály alkalmazásával a mapfunkciót az előző példa:

instance Functor [] where
  fmap = map

További példák a Functorfák:

-- a simple binary tree
data Tree a = Leaf a | Fork (Tree a) (Tree a)

instance Functor Tree where  
  fmap f (Leaf x) = Leaf (f x)
  fmap f (Fork l r) = Fork (fmap f l) (fmap f r)

A fa hozamának feltérképezése:

>>> fmap square (Fork (Fork (Leaf 1) (Leaf 2)) (Fork (Leaf 3) (Leaf 4)))
Fork (Fork (Leaf 1) (Leaf 4)) (Fork (Leaf 9) (Leaf 16))

Minden esetben a Functortípusú osztály, fmapa szerződésben köteles engedelmeskedni funktorhoz törvények:

fmap id       id              -- identity law
fmap (f . g)  fmap f . fmap g -- composition law

ahol a Haskell függvényösszetételét. jelöli .

Többek között ez lehetővé teszi elemi műveletek meghatározását különféle gyűjteményekhez .

Ezenkívül, ha F és G két functor, a természetes transzformáció a polimorf típusú függvény, amely tiszteletben tartja az fmap -t :

bármilyen funkcióhoz .

Ha a h függvényt paraméteres polimorfizmus határozza meg, mint a fenti típusdefinícióban, akkor ez a specifikáció mindig teljesül.

Optimalizálás

A térképek matematikai alapja számos optimalizálást tesz lehetővé . Az összetételi törvény biztosítja mindkettőt

  • (map f . map g) list és
  • map (f . g) list

ugyanarra az eredményre vezet; vagyis , . A második űrlapot azonban hatékonyabban lehet kiszámítani, mint az elsőt, mert mindegyikhez a teljes lista újratelepítése szükséges. Ezért a fordítók megpróbálják az első űrlapot a másodikra ​​alakítani; Az ilyen típusú optimalizálási ismert térkép fúzió és a funkcionális analógja hurok fúzió . map

A térképfüggvények olyan hajtogatással definiálhatók és gyakran definiálhatók, mint például foldr, ami azt jelenti, hogy egy térkép-hajtogatási fúziót lehet végezni : foldr f z . map gegyenértékű a következővel foldr (f . g) z.

A fenti térkép megvalósítása az egyedileg linkelt listákon nem farok-rekurzív , ezért sok keretet hozhat létre a veremben, ha nagy listával hívják meg. Sok nyelv felváltva biztosít "fordított térkép" funkciót, amely egyenértékű a leképezett lista megfordításával, de farok-rekurzív. Itt van egy megvalósítás, amely a fold -bal funkciót használja.

reverseMap f = foldl (\ys x -> f x : ys) []

Mivel az egyedileg linkelt lista megfordítása szintén farok-rekurzív, a fordított és a fordított térkép összeállítható a normál térkép farok-rekurzív módon történő végrehajtásához, bár a listán két áthaladást kell végrehajtani.

Nyelvi összehasonlítás

A térkép funkció funkcionális programozási nyelvekből származik.

A nyelv Lisp bevezetett egy térkép funkció az úgynevezett maplist1959-ben, némileg eltérő változatok már megjelent 1958-ban Ez az eredeti definíció maplist, és feltérképezi a funkció az egymást követő többi meg:

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

A funkció maplisttovábbra is elérhető az újabb Lisps -ekben, például a Common Lisp -ben , bár a hasonló mapcarvagy az általánosabb funkciókat maprészesítenék előnyben.

Négyszögesítése eleme egy listát maplistlenne írva S-expresszió jelölést, mint ez:

(maplist (lambda (l) (sqr (car l))) '(1 2 3 4 5))

A függvény használatával a mapcarfenti példát így írnánk:

(mapcar (function sqr) '(1 2 3 4 5))

Ma mapping funkciókat támogatja (vagy meg lehet határozni) számos eljárási , objektum-orientált , és multi-paradigma nyelveken is: A C ++ 's Standard Library , ez az úgynevezett std::transform, a C # (3,0)' s LINQ könyvtár, hanem ún Select. A Térkép gyakran használt művelet olyan magas szintű nyelveken is, mint a ColdFusion Markup Language (CFML), a Perl , a Python és a Ruby ; a műveletet mapmind a négy nyelven hívják . A Ruby collectalias mapis rendelkezésre áll (a Smalltalk -tól ). A Common Lisp térképszerű funkciók családját biztosítja; az itt leírt viselkedésnek megfelelőt hívják mapcar(a -carhozzáférést a CAR művelet segítségével jelzi ). Vannak olyan szintaktikai konstrukciójú nyelvek is, amelyek ugyanazt a funkcionalitást nyújtják, mint a térkép funkció.

A térképet néha úgy általánosítják, hogy elfogadja a kétdimenziós (2-argumentus) függvényeket, amelyek a felhasználó által szolgáltatott függvényt két lista megfelelő elemeire tudják alkalmazni. Egyes nyelvek erre speciális neveket használnak, például map2 vagy zipWith . Nyelvek explicit variadic funkciók lehetnek változatai térkép változó argumentumainak száma a támogatás változó argumentumainak száma funkciókat. A 2 vagy több listát tartalmazó térkép kezelési problémával szembesül, ha a listák különböző hosszúságúak. Különböző nyelvek különböznek ebben. Néhányan kivételt emelnek. Néhányan megállnak a legrövidebb lista lejárta után, és figyelmen kívül hagyják a többi lista további elemeit. Néhányan folytatják a leghosszabb lista hosszát, és a már befejeződött listák esetében adjanak át néhány helyőrző értéket az értéket jelző függvénynek.

A nyelvek, amelyek támogatják az első osztályú funkciók és kikészítéséhez , maplehet részben alkalmazták , hogy szüntesse meg a funkciót, hogy a művek csak az egyik értéket egy elemenkénti egyenértékű, hogy a művek egy egész tartály; például map squareegy Haskell -függvény, amely négyzetbe zárja a lista egyes elemeit.

Térkép különböző nyelveken
Nyelv Térkép Térkép 2 listák Térkép n listák Megjegyzések Különböző hosszúságú listák kezelése
APL func list list1 func list2 func/ list1 list2 list3 list4 Az APL tömbfeldolgozó képességei implicitvé teszik a térképhez hasonló műveleteket Hosszúság hiba, ha a lista hossza nem egyenlő vagy 1
Közös Lisp (mapcar func list) (mapcar func list1 list2) (mapcar func list1 list2 ...) megáll a legrövidebb lista hossza után
C ++ std::transform(begin, end, result, func) std::transform(begin1, end1, begin2, result, func) A fejléc <algoritmus>
kezdődik , vége , és eredményeként a bejárók
miatt van írva kezdődően eredmény
C# ienum.Select(func)
vagy
A selectzáradék
ienum1.Zip(ienum2, func) Selectegy kiterjesztési módszer A
ienum egy IEnumerable van
Zipbevezetve a .NET 4.0 -ban
Hasonlóan minden .NET nyelvben
a legrövidebb lista befejezése után leáll
CFML obj.map(func) Hol objvan tömb vagy szerkezet. funcérvként megkapja az egyes elemek értékét, indexét vagy kulcsát, valamint egy hivatkozást az eredeti objektumra.
Clojure (map func list) (map func list1 list2) (map func list1 list2 ...) a legrövidebb lista befejezése után leáll
D list.map!func zip(list1, list2).map!func zip(list1, list2, ...).map!func A StoppingPolicy a zip -hez adta meg: a legrövidebb, a leghosszabb vagy a RequestSameLength
Erlang lists:map(Fun, List) lists:zipwith(Fun, List1, List2) zipwith3 szintén elérhető A listáknak azonos hosszúságúnak kell lenniük
Elixír Enum.map(list, fun) Enum.zip(list1, list2) |> Enum.map(fun) List.zip([list1, list2, ...]) |> Enum.map(fun) a legrövidebb lista befejezése után leáll
F# List.map func list List.map2 func list1 list2 Funkciók léteznek más típusokhoz is ( Seq és Array ) Dob kivétel
Groovy list.collect(func) [list1 list2].transpose().collect(func) [list1 list2 ...].transpose().collect(func)
Haskell map func list zipWith func list1 list2 zipWithn func list1 list2 ... nmegfelel a listák számának; -ig előre definiáltzipWith7 a legrövidebb lista befejezése után leáll
Haxe array.map(func)
list.map(func)
Lambda.map(iterable, func)
J func list list1 func list2 func/ list1, list2, list3 ,: list4 J tömbfeldolgozó képességei implicitvé teszik a térképhez hasonló műveleteket hosszúság hiba, ha a lista hossza nem egyenlő
Java 8+ stream.map(func)
JavaScript 1.6
ECMAScript 5
array#map(func) List1.map(function (elem1, i) {
return func(elem1, List2[i]); })
List1.map(function (elem1, i) {
return func(elem1, List2[i], List3[i], ...); })
A#tömb térkép 3 érvet ad át a funcnak : az elemet, az elem indexét és a tömböt. A nem használt érvek elhagyhatók. A List1 végén áll meg , szükség esetén a rövidebb tömböket meghatározatlan elemekkel bővíti .
Julia map(func, list) map(func, list1, list2) map(func, list1, list2, ..., listN) HIBA: DimensionMismatch
Logtalk map(Closure, List) map(Closure, List1, List2) map(Closure, List1, List2, List3, ...) (up to seven lists) Csak a Bezárás érvet kell példányosítani. Kudarc
Mathematica func /@ list
Map[func, list]
MapThread[func, {list1, list2}] MapThread[func, {list1, list2, ...}] A listáknak azonos hosszúságúnak kell lenniük
Maxima map(f, expr1, ..., exprn)
maplist(f, expr1, ..., exprn)
a map egy olyan kifejezést ad vissza, amelynek vezető operátora megegyezik a kifejezésekével;
maplist egy listát ad vissza
OCaml List.map func list
Array.map func array
List.map2 func list1 list2 Invalid_argument kivételt vet fel
PARI/GP apply(func, list) N/A
Perl map block list
map expr, list
A blokk vagy exppr speciális $ _ változó sorban tartja a lista minden értékét. A Helper List::MoreUtils::each_arraytöbb listát kombinál, amíg a leghosszabb kimerül, és megtölti a többitundef.
PHP array_map(callable, array) array_map(callable, array1,array2) array_map(callable, array1,array2, ...) A lehívható paraméterek számának meg
kell egyeznie a tömbök számával.
kiterjeszti a rövidebb listákat NULL elemekkel
Bevezető maplist(Cont, List1, List2). maplist(Cont, List1, List2, List3). maplist(Cont, List1, ...). A lista argumentumai bemenet, kimenet vagy mindkettő. Subumes is zipWith, unzip, all Csendes hiba (nem hiba)
Piton map(func, list) map(func, list1, list2) map(func, list1, list2, ...) Visszaad egy listát a Python 2 -ben és egy iterátort a Python 3 -ban. zip()és map()(3.x) a legrövidebb lista befejezése után megáll, míg a map()(2.x) és itertools.zip_longest()(3.x) Noneelemekkel bővíti a rövidebb listákat
Rubin enum.collect {block}
enum.map {block}
enum1.zip(enum2).map {block} enum1.zip(enum2, ...).map {block}
[enum1, enum2, ...].transpose.map {block}
enum is an Enumeration megáll a meghívott objektum végén (az első lista); ha bármely más lista rövidebb, akkor nulla elemmel bővül
Rozsda list1.into_iter().map(func) list1.into_iter().zip(list2).map(func) a Iterator::mapés Iterator::zipmetódusok egyaránt átveszik az eredeti iterátor tulajdonjogát, és visszaadnak egy újat; a Iterator::zipmódszer belsőleg hívja be a IntoIterator::into_itermódszertlist2 a rövidebb lista befejezése után leáll
S - R lapply(list, func) mapply(func, list1, list2) mapply(func, list1, list2, ...) A rövidebb listák ciklusosak
Scala list.map(func) (list1, list2).zipped.map(func) (list1, list2, list3).zipped.map(func) Megjegyzés: 3 -nál több nem lehetséges. a rövidebb lista befejezése után leáll
Rendszer (beleértve a csalást és az ütést ) (map func list) (map func list1 list2) (map func list1 list2 ...) a listáknak azonos hosszúságúaknak kell lenniük (az SRFI-1 kiterjed a különböző hosszúságú listákra is)
Csevej aCollection collect: aBlock aCollection1 with: aCollection2 collect: aBlock Nem sikerül
Szabványos ML map func list ListPair.map func (list1, list2)
ListPair.mapEq func (list1, list2)
A 2 argumentumú térképeknél a func egy sorban veszi az érveit ListPair.mapleáll a legrövidebb lista befejezése után, míg kivételt ListPair.mapEqokozUnequalLengths
Gyors sequence.map(func) zip(sequence1, sequence2).map(func) a legrövidebb lista befejezése után leáll
XPath 3
XQuery 3
list ! block
for-each(list, func)
for-each-pair(list1, list2, func) A blockkontextusban az elem .az aktuális értéket tartalmazza a legrövidebb lista befejezése után leáll

Lásd még

Hivatkozások