Mereka terlihat sama di situs aplikasi tetapi mereka berbeda, tentunya. Saat Anda menerapkan salah satu dari dua fungsi tersebut, map
atau fmap
, ke daftar nilai, keduanya akan menghasilkan hasil yang sama tetapi itu tidak berarti fungsi tersebut dimaksudkan untuk tujuan yang sama.
Jalankan sesi GHCI (Glasgow Haskell Compiler Interactive) untuk meminta informasi tentang kedua fungsi tersebut, kemudian lihat implementasinya dan Anda akan menemukan banyak perbedaan.
peta
Tanya GHCI untuk informasi tentang map
Prelude> :info map
map :: (a -> b) -> [a] -> [b] -- Defined in ‘GHC.Base’
dan Anda akan melihatnya ditetapkan sebagai fungsi tingkat tinggi yang berlaku untuk daftar nilai jenis apa pun a
menghasilkan daftar nilai jenis apa pun b
. Meskipun polimorfik ( a
dan b
dalam definisi di atas berarti semua tipe) map
fungsi ini dimaksudkan untuk diterapkan ke daftar nilai yang hanya merupakan satu tipe data yang mungkin di antara banyak tipe data lainnya di Haskell. The map
Fungsi tidak dapat diterapkan untuk sesuatu yang bukan merupakan daftar nilai.
Seperti yang dapat Anda baca dari kode sumber GHC.Base , map
fungsi tersebut diimplementasikan sebagai berikut
map _ [] = []
map f (x:xs) = f x : map f xs
yang memanfaatkan pencocokan pola untuk menarik kepala (the x
) dari ekor (thexs
) dari daftar, kemudian membuat daftar baru dengan menggunakan :
konstruktor nilai (kontra) sehingga untuk menambahkan f x
(baca sebagai "f diterapkan ke x" ) ke rekursi map
melewati ekor sampai daftar kosong. Perlu diperhatikan bahwa implementasi map
fungsi tidak bergantung pada fungsi lain tetapi hanya pada dirinya sendiri.
fmap
Sekarang coba untuk menanyakan informasi tentang fmap
dan Anda akan melihat sesuatu yang sangat berbeda.
Prelude> :info fmap
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
...
-- Defined in ‘GHC.Base’
Kali fmap
ini didefinisikan sebagai salah satu fungsi yang implementasinya harus disediakan oleh tipe data yang ingin dimiliki Functor
kelas tipe. Artinya, bisa ada lebih dari satu tipe data, tidak hanya "daftar nilai" , yang dapat menyediakan implementasi untuk fmap
fungsi tersebut. Itu membuat fmap
dapat diterapkan ke kumpulan tipe data yang jauh lebih besar: fungtor memang!
Seperti yang dapat Anda baca dari kode sumber GHC.Base , kemungkinan implementasi fmap
fungsi adalah yang disediakan olehMaybe
tipe data:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
dan implementasi lain yang mungkin adalah yang disediakan oleh tipe data 2-tupel
instance Functor ((,) a) where
fmap f (x,y) = (x, f y)
dan kemungkinan implementasi lainnya adalah yang disediakan oleh tipe data daftar (tentu saja!):
instance Functor [] where
fmap f xs = map f xs
yang bergantung pada map
fungsinya.
Kesimpulan
The map
fungsi dapat diterapkan untuk tidak lebih dari daftar nilai (di mana nilai-nilai dari jenis apa pun) sedangkan fmap
fungsi dapat diterapkan tipe data jauh lebih: semua orang yang termasuk kelas functor (misalnya maybes, tupel, daftar, dll ). Karena tipe data "daftar nilai" juga berfungsi (karena menyediakan implementasi untuknya), maka fmap
dapat diterapkan juga menghasilkan hasil yang sama seperti map
.
map (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)