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.