Haskell - Functor
Functorw Haskell jest rodzajem funkcjonalnej reprezentacji różnych typów, które można odwzorować. Jest to koncepcja wysokiego poziomu implementacji polimorfizmu. Według twórców Haskell, wszystkie typy, takie jak Lista, Mapa, Drzewo, itp. Są instancjami Haskell Functor.
ZA Functor jest klasą wbudowaną z definicją funkcji taką jak -
class Functor f where
fmap :: (a -> b) -> f a -> f b
Na podstawie tej definicji możemy wywnioskować, że plik Functor jest funkcją, która przyjmuje funkcję, powiedzmy, fmap()i zwraca inną funkcję. W powyższym przykładziefmap() jest uogólnioną reprezentacją funkcji map().
W poniższym przykładzie zobaczymy, jak działa Haskell Functor.
main = do
print(map (subtract 1) [2,4,8,16])
print(fmap (subtract 1) [2,4,8,16])
Tutaj użyliśmy obu map() i fmap()nad listą operacji odejmowania. Można zauważyć, że obie instrukcje dadzą ten sam wynik listy zawierającej elementy [1,3,7,15].
Obie funkcje nazywały się inną funkcją o nazwie subtract() aby dać wynik.
[1,3,7,15]
[1,3,7,15]
Jaka jest różnica między map i fmap? Różnica polega na ich zastosowaniu. Functor pozwala nam zaimplementować więcej funkcjonalistów w różnych typach danych, takich jak „tylko” i „nic”.
main = do
print (fmap (+7)(Just 10))
print (fmap (+7) Nothing)
Powyższy fragment kodu przyniesie następujący wynik na terminalu -
Just 17
Nothing
Funktor aplikacyjny
Funktor aplikacyjny to normalny funktor z kilkoma dodatkowymi cechami zapewnianymi przez klasę typów aplikacyjnych.
Używając Functora, zwykle mapujemy istniejącą funkcję na inną zdefiniowaną w niej funkcję. Ale nie ma sposobu, aby odwzorować funkcję zdefiniowaną wewnątrz Functora z innym Functorem. Dlatego mamy inny obiekt o nazwieApplicative Functor. Ta możliwość mapowania jest implementowana przez klasę Applicative Type zdefiniowaną wControlmoduł. Ta klasa daje nam tylko dwie metody do pracy: jedna topure a drugi jest <*>.
Poniżej znajduje się definicja klasy Applicative Functor.
class (Functor f) => Applicative f where
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
Zgodnie z implementacją możemy zmapować innego Functora na dwa sposoby: "Pure" i "<*>". Metoda „Pure” powinna przyjmować wartość dowolnego typu i zawsze zwraca Applicative Functor o tej wartości.
Poniższy przykład pokazuje, jak działa Applicative Functor -
import Control.Applicative
f1:: Int -> Int -> Int
f1 x y = 2*x+y
main = do
print(show $ f1 <$> (Just 1) <*> (Just 2) )
Tutaj zaimplementowaliśmy funktory aplikacyjne w wywołaniu funkcji f1. Nasz program da następujący wynik.
"Just 4"
Monoidy
Wszyscy wiemy, że Haskell definiuje wszystko w postaci funkcji. W funkcjach mamy opcje, aby uzyskać nasze dane wejściowe jako dane wyjściowe funkcji. To właśnie jestMonoid jest.
ZA Monoidto zbiór funkcji i operatorów, których dane wyjściowe są niezależne od danych wejściowych. Weźmy funkcję (*) i liczbę całkowitą (1). Teraz, cokolwiek może być wejściem, jego wyjście pozostanie tylko tą samą liczbą. Oznacza to, że jeśli pomnożysz liczbę przez 1, otrzymasz tę samą liczbę.
Oto definicja monoidu w klasie typu.
class Monoid m where
mempty :: m
mappend :: m -> m -> m
mconcat :: [m] -> m
mconcat = foldr mappend mempty
Spójrz na poniższy przykład, aby zrozumieć użycie Monoid w Haskell.
multi:: Int->Int
multi x = x * 1
add :: Int->Int
add x = x + 0
main = do
print(multi 9)
print (add 7)
Nasz kod wygeneruje następujący wynik -
9
7
W tym przypadku funkcja „multi” mnoży wejście przez „1”. Podobnie funkcja „add” dodaje wejście z „0”. W obu przypadkach dane wyjściowe będą takie same jak dane wejściowe. Stąd funkcje{(*),1} i {(+),0} to doskonałe przykłady monoidów.