Harita (üst düzey işlev) - Map (higher-order function)

Birçok olarak programlama dilleri , harita bir adıdır yüksek mertebeden fonksiyonu bir uygular verilen fonksiyon bir her elemana funktor örneğin bir, listede aynı sırada sonuçların listesini dönen,. İşlevsel formda düşünüldüğünde genellikle herkese uygulanır olarak adlandırılır .

Harita kavramı listelerle sınırlı değildir: sıralı kaplar , ağaç benzeri kaplar ve hatta vadeli işlemler ve vaatler gibi soyut kaplar için çalışır .

Örnekler: bir listeyi eşleme

Bir tamsayı listemiz olduğunu [1, 2, 3, 4, 5]ve her tamsayının karesini hesaplamak istediğimizi varsayalım . Bunu yapmak için önce squaretek bir sayıya bir fonksiyon tanımlarız (burada Haskell 'de gösterilmiştir ):

square x = x * x

sonra arayabiliriz

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

hangi verir [1, 4, 9, 16, 25], maptüm listeden geçtiğini ve işlevi squareher öğeye uyguladığını gösterir.

Görsel örnek

Aşağıda, işleve göre X = [0, 5, 8, 3, 2, 1]yeni bir listeye eşlemek istediğimiz tamsayıların bir listesi için eşleme sürecinin her adımının bir görünümünü görebilirsiniz  : X'

harita işlevi işleme adımlarını uygulama
Bir listede harita işlevi uygularken işlem adımlarının görünümü

mapHaskell'ın taban başlangıcı (yani "standart kütüphanesi") bir parçası olarak sağlanır ve şekilde uygulanır:

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

genelleme

Haskell'de polimorfik fonksiyonu map :: (a -> b) -> [a] -> [b] a genelleştirilmiş polytypic fonksiyonu fmap :: Functor f => (a -> b) -> f a -> f b ait herhangi bir türü için geçerli olan, tip sınıfı . Functor

Bir tipte listelerinin []bir örneği olarak tanımlanabilir Functorkullanılarak tip sınıfı mapÖnceki örnekten elde edilen işlevi:

instance Functor [] where
  fmap = map

Örneklerin diğer örnekleri Functorarasında ağaçlar bulunur:

-- 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)

Bir ağaç üzerinde eşleme şu sonuçları verir:

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

FunctorType sınıfının her örneği için fmap, sözleşmeye dayalı olarak functor yasalarına uymakla yükümlüdür :

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

burada Haskell'deki işlev bileşimini. belirtir .

Diğer kullanımların yanı sıra, bu, çeşitli koleksiyon türleri için eleman bazında işlemlerin tanımlanmasına izin verir .

Ayrıca, eğer F ve G, iki funktorlar olan, bir doğal dönüşüm polimorfik tür bir fonksiyonudur açıdan fmap :

herhangi bir işlev için .

Eğer h fonksiyonu ile tanımlanır parametrik polimorfizm yukarıdaki tip tanımı olarak, bu şartnamenin her zaman tatmin edilir.

Optimizasyonlar

Haritaların matematiksel temeli, bir dizi optimizasyona izin verir . Kompozisyon yasası, her ikisinin de

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

aynı sonuca yol açar; yani, . Bununla birlikte, ikinci formun hesaplanması ilk forma göre daha verimlidir, çünkü her biri bir listenin tamamını sıfırdan yeniden oluşturmayı gerektirir. Bu nedenle, derleyiciler ilk formu ikinciye dönüştürmeye çalışacaklardır; bu tür optimizasyon, harita füzyonu olarak bilinir ve döngü füzyonunun işlevsel analoğudur . map

Harita işlevleri, örneğin bir katlama cinsinden tanımlanabilir ve sıklıkla tanımlanır foldr; bu, birinin bir harita katlama füzyonu yapılabileceği anlamına gelir : foldr f z . map geşdeğerdir foldr (f . g) z.

Yukarıdaki haritanın tek başına bağlantılı listelerde uygulanması kuyruk özyinelemeli değildir , bu nedenle büyük bir listeyle çağrıldığında yığında çok sayıda çerçeve oluşturabilir. Birçok dil, dönüşümlü olarak, eşlenmiş bir listeyi tersine çevirmeye eşdeğer, ancak kuyruk özyinelemeli bir "ters eşleme" işlevi sağlar. İşte fold -left işlevini kullanan bir uygulama .

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

Tekil bağlantılı bir listeyi tersine çevirmek de kuyruk özyinelemeli olduğundan, normal haritayı kuyruk özyinelemeli bir şekilde gerçekleştirmek için ters ve ters harita oluşturulabilir, ancak liste üzerinde iki geçiş yapılmasını gerektirir.

Dil karşılaştırması

Harita işlevi, işlevsel programlama dillerinde ortaya çıkmıştır .

Lisp dili maplist, 1959'da adı verilen ve 1958'de zaten görünen biraz farklı sürümleri olan bir harita işlevi tanıttı . Bu, maplistardışık dinlenme listeleri üzerinde bir işlevi eşlemek için orijinal tanımdır :

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

Bu işlev maplist, Common Lisp gibi daha yeni Lisp'lerde hala mevcuttur , ancak benzeri mapcarveya daha genel olan işlevler maptercih edilir.

Bir listenin öğelerini kullanarak kare almak, S-ifadesi notasyonunda maplistşu şekilde yazılır :

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

Fonksiyonu kullanarak mapcar, yukarıdaki örnek şu şekilde yazılır:

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

Günümüzde eşleme işlevleri birçok prosedürel , nesne yönelimli ve çok paradigmalı dilde de desteklenmektedir (veya tanımlanabilir) : C++ 'ın Standart Kitaplığında buna std::transform, C# (3.0)'ın LINQ kitaplığında denir. adlı bir uzatma yöntemi olarak sağlanır Select. Harita ayrıca ColdFusion Markup Language (CFML), Perl , Python ve Ruby gibi yüksek seviyeli dillerde sıklıkla kullanılan bir işlemdir ; işlem mapbu dillerin dördünde de çağrılır . Ruby'de ( Smalltalk'tan ) collectiçin bir takma ad mapda sağlanır . Common Lisp , bir harita benzeri işlevler ailesi sağlar; burada açıklanan davranışa karşılık gelen çağrılır ( CAR işlemini kullanarak erişimi gösterir ). Harita işleviyle aynı işlevselliği sağlayan sözdizimsel yapılara sahip diller de vardır. mapcar-car

Harita bazen, kullanıcı tarafından sağlanan bir işlevi iki listeden karşılık gelen öğelere uygulayabilen ikili (2-argüman) işlevleri kabul edecek şekilde genelleştirilir. Bazı diller gibi bunun için özel adlar kullanın map2 veya zipWith . Açık değişken işlevleri kullanan diller , değişken işlevli işlevleri desteklemek için değişken eşlilikli harita sürümlerine sahip olabilir . 2 veya daha fazla liste içeren harita, listeler farklı uzunlukta olduğunda ele alma sorunuyla karşılaşır. Bu konuda çeşitli diller farklıdır. Bazıları bir istisna oluşturur. Bazıları en kısa listenin uzunluğundan sonra durur ve diğer listelerdeki fazlalıkları görmezden gelir. Bazıları en uzun listenin uzunluğuna kadar devam eder ve zaten sona eren listeler için, değer olmadığını belirten işleve bir yer tutucu değeri iletir.

Destekleyen diller birinci sınıf işlevleri ve tımar , mapolabilir , kısmen tatbik için asansör bir işlevi olduğunu öğeye eşdeğer tek bir değer çalışmaları bu bütün bir kap üzerinde çalışır; örneğin, map squarebir listenin her öğesinin karesini alan bir Haskell işlevidir.

Çeşitli dillerde harita
Dilim Harita Harita 2 listesi Harita n listeleri Notlar Farklı uzunluklardaki listeleri işleme
APL func list list1 func list2 func/ list1 list2 list3 list4 APL'nin dizi işleme yetenekleri, harita gibi işlemleri örtük hale getirir liste uzunlukları eşit değilse veya 1 değilse uzunluk hatası
Ortak Lisp (mapcar func list) (mapcar func list1 list2) (mapcar func list1 list2 ...) en kısa listenin uzunluğundan sonra durur
C++ std::transform(begin, end, result, func) std::transform(begin1, end1, begin2, result, func) başlık <algoritma>
başlaması , sonu ve sonucu yineleyiciler olan
sonuç yazılır başlayan sonucu
C# ienum.Select(func)
ya da maddesi
select
ienum1.Zip(ienum2, func) Selectbir uzantı yöntemidir
ienum bir IEnumerable'dır
Zip.NET 4.0'da tanıtılmıştır
Benzer şekilde tüm .NET dillerinde
en kısa liste bittikten sonra durur
CFML obj.map(func) objBir dizi veya yapı nerede . funcargüman olarak her öğenin değerini, indeksini veya anahtarını ve orijinal nesneye bir referans alır.
Clojure (map func list) (map func list1 list2) (map func list1 list2 ...) en kısa liste bittikten sonra durur
NS list.map!func zip(list1, list2).map!func zip(list1, list2, ...).map!func StoppingPolicy tarafından sıkıştırılacağı belirtildi: en kısa, en uzun veya gerekliSameLength
Erlang lists:map(Fun, List) lists:zipwith(Fun, List1, List2) zipwith3 Ayrıca mevcut Listeler eşit uzunlukta olmalıdır
iksir Enum.map(list, fun) Enum.zip(list1, list2) |> Enum.map(fun) List.zip([list1, list2, ...]) |> Enum.map(fun) en kısa liste bittikten sonra durur
F# List.map func list List.map2 func list1 list2 Diğer türler için işlevler mevcuttur ( Seq ve Array ) İstisna atar
harika 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 ... nliste sayısına karşılık gelir; önceden tanımlanmışzipWith7 en kısa liste bittikten sonra durur
Haxe array.map(func)
list.map(func)
Lambda.map(iterable, func)
J func list list1 func list2 func/ list1, list2, list3 ,: list4 J'nin dizi işleme yetenekleri, harita gibi işlemleri örtük hale getirir liste uzunlukları eşit değilse uzunluk hatası
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], ...); })
Array#map, func öğesine 3 bağımsız değişken iletir : öğe, öğenin dizini ve dizi. Kullanılmayan argümanlar atlanabilir. Sonunda durur List1 ile kısa diziler uzanan, tanımsız gerekirse öğeler.
Julia map(func, list) map(func, list1, list2) map(func, list1, list2, ..., listN) HATA: Boyut Uyuşmazlığı
günlük konuşma map(Closure, List) map(Closure, List1, List2) map(Closure, List1, List2, List3, ...) (up to seven lists) Yalnızca Kapanış bağımsız değişkeni somutlaştırılmalıdır. Arıza
matematik func /@ list
Map[func, list]
MapThread[func, {list1, list2}] MapThread[func, {list1, list2, ...}] Listeler aynı uzunlukta olmalıdır
maksimum map(f, expr1, ..., exprn)
maplist(f, expr1, ..., exprn)
map, önde gelen operatörün ifadelerinkiyle aynı olduğu bir ifade döndürür;
maplist bir liste döndürür
OCaml List.map func list
Array.map func array
List.map2 func list1 list2 Invalid_argument istisnasını yükseltir
PARI/GP apply(func, list) Yok
Perl map block list
map expr, list
Gelen bloğun veya İfade özel değişken $ _ sırayla listeden her değerini tutar. Helper List::MoreUtils::each_array, en uzun olan bitene kadar birden fazla listeyi birleştirir, diğerleriniundef.
PHP array_map(callable, array) array_map(callable, array1,array2) array_map(callable, array1,array2, ...) Çağrılabilir parametre
sayısı, dizi sayısıyla eşleşmelidir.
NULL öğelerle daha kısa listeleri genişletir
Prolog maplist(Cont, List1, List2). maplist(Cont, List1, List2, List3). maplist(Cont, List1, ...). Liste argümanları girdi, çıktı veya her ikisidir. Ayrıca zipWith, unzip, all içerir Sessiz arıza (hata değil)
piton map(func, list) map(func, list1, list2) map(func, list1, list2, ...) Python 2'de bir liste ve Python 3'te bir yineleyici döndürür. zip()ve map()(3.x) en kısa liste sona erdikten sonra durur, oysa map()(2.x) ve itertools.zip_longest()(3.x) daha kısa listeleri Noneöğelerle genişletir
yakut 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 çağrıldığı nesnenin sonunda durur (ilk liste); başka bir liste daha kısaysa, sıfır öğelerle genişletilir
Pas list1.into_iter().map(func) list1.into_iter().zip(list2).map(func) Iterator::mapve Iterator::zipyöntemler hem take orijinal yineleyici mülkiyeti ve yenisini return; Iterator::zipyöntem dahili olarak çağırır IntoIterator::into_iteryöntemi üzerindelist2 kısa liste bittikten sonra durur
S - Sağ lapply(list, func) mapply(func, list1, list2) mapply(func, list1, list2, ...) Daha kısa listeler döngüye alınır
Skala list.map(func) (list1, list2).zipped.map(func) (list1, list2, list3).zipped.map(func) not: 3'ten fazla mümkün değil. kısa liste bittikten sonra durur
Şema ( Guile ve Racket dahil ) (map func list) (map func list1 list2) (map func list1 list2 ...) listelerin hepsinin aynı uzunlukta olması gerekir (SRFI-1, farklı uzunluktaki listeleri alacak şekilde genişler)
küçük konuşma aCollection collect: aBlock aCollection1 with: aCollection2 collect: aBlock başarısız
standart makine öğrenimi map func list ListPair.map func (list1, list2)
ListPair.mapEq func (list1, list2)
2-argüman haritası için func , argümanlarını bir demet içinde alır ListPair.mapen kısa liste sona erdikten sonra durur ListPair.mapEq, UnequalLengthsistisna oluşturur
Süratli sequence.map(func) zip(sequence1, sequence2).map(func) en kısa liste bittikten sonra durur
XPath 3
XQuery 3
list ! block
for-each(list, func)
for-each-pair(list1, list2, func) Gelen blockbağlam öğe .şimdiki değeri tutan en kısa liste bittikten sonra durur

Ayrıca bakınız

Referanslar