Wyglądają tak samo w witrynie aplikacji, ale są oczywiście inne. Po zastosowaniu jednej z tych dwóch funkcji maplubfmap do listy wartości, dadzą one ten sam wynik, ale to nie znaczy, że są przeznaczone do tego samego celu.
Uruchom sesję GHCI (Glasgow Haskell Compiler Interactive), aby uzyskać informacje o tych dwóch funkcjach, a następnie spójrz na ich implementacje, a odkryjesz wiele różnic.
mapa
Zapytaj GHCI o informacje na temat map
Prelude> :info map
map :: (a -> b) -> [a] -> [b]
i zobaczysz, że jest zdefiniowana jako funkcja wysokiego rzędu mająca zastosowanie do listy wartości dowolnego typu, adająca listę wartości dowolnego typu b. Chociaż polimorficzna ( aiw bpowyższej definicji oznacza dowolny typ), mapfunkcja ma być stosowana do listy wartości, która jest tylko jednym możliwym typem danych spośród wielu innych w Haskell. PlikmapFunkcja nie może być stosowana do czegoś, co nie jest listą wartości.
Jak można przeczytać z kodu źródłowego GHC.Base , mapfunkcja jest zaimplementowana w następujący sposób
map _ [] = []
map f (x:xs) = f x : map f xs
który wykorzystuje dopasowanie do wzorca, aby wyciągnąć początek (the x) z końca (the xs) listy, a następnie konstruuje nową listę przy użyciu :konstruktora wartości (minusy), tak aby poprzedzać f x(czytaj jako "f zastosowane do x" ) do rekurencji mapover the tail, aż lista będzie pusta. Warto zauważyć, że implementacjamap funkcji nie zależy od żadnej innej funkcji, ale tylko od siebie.
fmap
Teraz spróbuj zapytać o informacje, fmapa zobaczysz coś zupełnie innego.
Prelude> :info fmap
class Functor (f :: * -> *) where
fmap :: (a -> b) -> f a -> f b
...
Czas fmapten definiuje się jako jedną z funkcji, której implementacje muszą być zapewnione przez te typy danych, które chcą należeć do Functorklasy typów. Oznacza to, że może istnieć więcej niż jeden typ danych, nie tylko typ danych „lista wartości” , który może zapewnić implementację fmapfunkcji. To ma fmapzastosowanie do znacznie większego zestawu typów danych: rzeczywiście funktorów!
Jak można wyczytać z kodu źródłowego GHC.Base , możliwą implementacją fmapfunkcji jest ta, którą zapewnia Maybetyp danych:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
a inną możliwą implementacją jest ta zapewniana przez typ danych 2-krotkowych
instance Functor ((,) a) where
fmap f (x,y) = (x, f y)
a inną możliwą implementacją jest ta dostarczona przez typ danych listy (oczywiście!):
instance Functor [] where
fmap f xs = map f xs
który opiera się na map funkcji.
Wniosek
mapFunkcja może być stosowany do niczego więcej niż listy wartości (gdzie wartości są z każdego rodzaju), natomiast fmapfunkcja może być stosowana znacznie więcej typów danych: wszystkie te, które należą do klasy funktora (np maybes, krotki, listy, etc. ). Ponieważ typ danych „lista wartości” jest również funktorem (ponieważ zapewnia jego implementację), fmapmożna go zastosować do programu, dając dokładnie taki sam wynik jak map.
map (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)