Doszedłem do tego postu, aby lepiej zrozumieć wniosek o niesławnym cytacie z teorii kategorii Mac Lane'a dla pracującego matematyka .
Opisując, czym jest, często równie przydatne jest opisanie tego, czym nie jest.
Fakt, że Mac Lane używa opisu do opisu Monady, może sugerować, że opisuje on coś unikalnego dla Monad. Zrób ze mną. Aby rozwinąć szersze zrozumienie tego oświadczenia, uważam, że należy wyjaśnić, że tak jest nie opisuje on czegoś, co jest unikalne dla monad; oświadczenie w równym stopniu opisuje między innymi aplikację i strzałki. Z tego samego powodu możemy mieć dwa monoidy na Int (suma i iloczyn), możemy mieć kilka monoidów na X w kategorii endofunkcji. Ale podobieństw jest jeszcze więcej.
Zarówno Monad, jak i Wnioskodawca spełniają kryteria:
W instrukcji użyto „Kategoria ...”. Definiuje zakres instrukcji. Jako przykład, funktor Kategoria opisuje zakres f * -> g *
, czyli Any functor -> Any functor
np Tree * -> List *
lubTree * -> Tree *
.
To, czego nie określa stwierdzenie kategoryczne, opisuje, gdzie wszystko i wszystko jest dozwolone .
W tym przypadku wewnątrz funktorów * -> *
aka a -> b
nie jest określona, co oznacza Anything -> Anything including Anything else
. Gdy moja wyobraźnia przeskakuje do Int -> String, zawiera także Integer -> Maybe Int
, a nawet Maybe Double -> Either String Int
gdzie a :: Maybe Double; b :: Either String Int
.
Zatem zestawienie składa się w następujący sposób:
- zakres funktora
:: f a -> g b
(tj. dowolny sparametryzowany typ do dowolnego sparametryzowanego typu)
- endo + funktor
:: f a -> f b
(tj. dowolny sparametryzowany typ do tego samego sparametryzowanego typu) ... powiedział inaczej,
- monoid w kategorii endofunkcji
Gdzie zatem jest moc tego konstruktu? Aby docenić pełną dynamikę, musiałem zobaczyć, że typowe rysunki monoidu (pojedynczy obiekt z czymś, co wygląda jak strzałka tożsamości :: single object -> single object
), nie pokazują, że wolno mi użyć strzałki sparametryzowanej z dowolną liczbą wartości monoidów, z obiektu jednego typu dozwolonego w Monoid. Definicja równoważności strzałki endo ~ ~ ignoruje wartość typu funktora, a także rodzaj i wartość najbardziej wewnętrznej warstwy „ładunku”. Zatem równoważność zwraca się true
w każdej sytuacji, w której typy funktorów pasują do siebie (np. Nothing -> Just * -> Nothing
Jest równoważne, Just * -> Just * -> Just *
ponieważ oba są oba Maybe -> Maybe -> Maybe
).
Pasek boczny: ~ na zewnątrz jest koncepcyjny, ale jest najbardziej lewym symbolem w f a
. Opisuje również, co „Haskell” wczytuje jako pierwsze (duży obrazek); więc typ jest „zewnętrzny” w stosunku do wartości typu. Relacja między warstwami (łańcuchem odniesień) w programowaniu nie jest łatwa do odniesienia w kategorii. Kategoria zestawu służy do opisywania typów (Int, Strings, Może Int itp.), Która obejmuje kategorię Functor (typy sparametryzowane). Łańcuch referencyjny: Typ Functora, Wartości Functora (elementy zestawu Functora, np. Nic, Tylko), a z kolei wszystko inne, na co wskazuje każda wartość funktora. W kategorii związek jest opisany inaczej, np. return :: a -> m a
Jest uważany za naturalną transformację z jednego Functora na inny Functor, różny od wszystkiego, co wspomniano do tej pory.
Wracając do głównego wątku, w sumie, dla dowolnego zdefiniowanego produktu tensorowego i wartości neutralnej, stwierdzenie kończy się niesamowicie potężnym konstruktem obliczeniowym zrodzonym z jego paradoksalnej struktury:
- na zewnątrz pojawia się jako pojedynczy obiekt (np.
:: List
); statyczny
- ale wewnątrz pozwala na dużą dynamikę
- dowolna liczba wartości tego samego typu (np. Empty | ~ NonEmpty) co pasza dla funkcji dowolnego arsenału. Tensor zredukuje dowolną liczbę danych wejściowych do jednej wartości ... dla warstwy zewnętrznej (~
fold
nie mówi nic o ładunku)
- nieskończony zakres zarówno typu, jak i wartości dla najbardziej wewnętrznej warstwy
W Haskell wyjaśnienie stosowalności oświadczenia jest ważne. Moc i wszechstronność tego konstruktu nie ma absolutnie nic wspólnego z monadą samą w sobie . Innymi słowy, konstrukcja nie opiera się na tym, co czyni monadę wyjątkową.
Próbując dowiedzieć się, czy zbudować kod w kontekście współużytkowanym w celu obsługi obliczeń, które są od siebie zależne, w porównaniu z obliczeniami, które można uruchamiać równolegle, ta niesławna instrukcja, o ile opisuje, nie stanowi kontrastu między wyborem Zastosowanie, strzały i monady, ale raczej opis, jak bardzo są takie same. W przypadku podjętej decyzji stwierdzenie jest dyskusyjne.
Jest to często źle rozumiane. Stwierdzenie to opisuje dalej join :: m (m a) -> m a
jako iloczyn tensorowy monoidalnego endofunkcji. Nie precyzuje jednak, jak w kontekście tego oświadczenia (<*>)
można było również wybrać. To naprawdę przykład sześciu / pół tuzina. Logika łączenia wartości jest dokładnie taka sama; te same dane wejściowe generują takie same dane wyjściowe z każdego z nich (w przeciwieństwie do monoidów Sum i Produkt dla Int, ponieważ generują różne wyniki podczas łączenia Ints).
Podsumowując: monoid w kategorii endofunkcji opisuje:
~t :: m * -> m * -> m *
and a neutral value for m *
(<*>)
i (>>=)
oba zapewniają jednoczesny dostęp do dwóch m
wartości w celu obliczenia pojedynczej wartości zwracanej. Logika zastosowana do obliczenia wartości zwracanej jest dokładnie taka sama. Gdyby nie to, dla różnych kształtów funkcji ich parametryzacji ( f :: a -> b
kontra k :: a -> m b
) oraz pozycji parametru tego samego typu zwracanej obliczeń (tj, a -> b -> b
w porównaniu b -> a -> b
do siebie odpowiednio), podejrzewam, że nie mogliśmy zostać sparametryzowane w monoidal cyfrowym, produkt tensorowy do ponownego użycia w obu definicjach. Jako ćwiczenie, które ma sens, spróbuj wdrożyć ~t
, a skończysz na tym (<*>)
iw (>>=)
zależności od tego, jak zdecydujesz się go zdefiniować forall a b
.
Jeśli mój ostatni punkt jest przynajmniej koncepcyjnie prawdziwy, to wyjaśnia dokładną i jedyną różnicę obliczeniową między Applicative i Monad: funkcje, które sparametryzują. Innymi słowy, różnica jest zewnętrzna w stosunku do implementacji tych klas typów.
Podsumowując, z własnego doświadczenia, niesławny cytat Mac Lane'a dostarczył świetnego memu „goto”, który był dla mnie drogowskazem podczas nawigacji przez kategorię, aby lepiej zrozumieć idiomy używane w Haskell. Udało mu się uchwycić zakres potężnej mocy obliczeniowej, doskonale dostępnej w Haskell.
Jednak ironia polega na tym, że po raz pierwszy źle zrozumiałem zastosowanie tego oświadczenia poza monadą i to, co mam nadzieję tu przekazać. Wszystko, co opisuje, okazuje się być podobne między Applicative a Monadami (i innymi strzałkami). To, czego nie mówi, to dokładnie małe, ale użyteczne rozróżnienie między nimi.
- E