Mereka terlihat sama di situs aplikasi tetapi mereka berbeda, tentunya. Saat Anda menerapkan salah satu dari dua fungsi tersebut, mapatau 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 ( adan bdalam definisi di atas berarti semua tipe) mapfungsi ini dimaksudkan untuk diterapkan ke daftar nilai yang hanya merupakan satu tipe data yang mungkin di antara banyak tipe data lainnya di Haskell. The mapFungsi tidak dapat diterapkan untuk sesuatu yang bukan merupakan daftar nilai.
Seperti yang dapat Anda baca dari kode sumber GHC.Base , mapfungsi 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 mapmelewati ekor sampai daftar kosong. Perlu diperhatikan bahwa implementasi mapfungsi tidak bergantung pada fungsi lain tetapi hanya pada dirinya sendiri.
fmap
Sekarang coba untuk menanyakan informasi tentang fmapdan 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 fmapini didefinisikan sebagai salah satu fungsi yang implementasinya harus disediakan oleh tipe data yang ingin dimiliki Functorkelas tipe. Artinya, bisa ada lebih dari satu tipe data, tidak hanya "daftar nilai" , yang dapat menyediakan implementasi untuk fmapfungsi tersebut. Itu membuat fmapdapat diterapkan ke kumpulan tipe data yang jauh lebih besar: fungtor memang!
Seperti yang dapat Anda baca dari kode sumber GHC.Base , kemungkinan implementasi fmapfungsi 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 mapfungsinya.
Kesimpulan
The mapfungsi dapat diterapkan untuk tidak lebih dari daftar nilai (di mana nilai-nilai dari jenis apa pun) sedangkan fmapfungsi 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 fmapdapat diterapkan juga menghasilkan hasil yang sama seperti map.
map (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)