Wnioskodawcy tworzą, monady nie.
Co oznacza powyższe stwierdzenie? A kiedy jedno jest lepsze od drugiego?
haskell
functional-programming
monads
monad-transformers
applicative
missingfaktor
źródło
źródło
Applicative
s są w rzeczywistości cała rodzina odMonad
s, a mianowicie po jednym dla każdego „kształt” struktury możliwe.ZipList
nie jest aMonad
, aleZipList
s o stałej długości są.Reader
jest wygodnym przypadkiem specjalnym (czy raczej ogólnym?), w którym rozmiar „struktury” jest ustalony jako liczność typu środowiska.Reader
sprowadza się do monady aż do izomorfizmu. Po ustaleniu kształtu kontenera skutecznie koduje on funkcję z pozycji, takich jak notatka. Peter Hancock nazywa takie funktory „naperianem”, ponieważ podlegają one prawom logarytmów.Odpowiedzi:
Jeśli porównamy typy
otrzymujemy wskazówkę, co oddziela te dwa pojęcia. To
(s -> m t)
w typie(>>=)
pokazuje, że wartość ws
może określać zachowanie obliczenia wm t
. Monady pozwalają na interferencję między warstwami wartości i obliczeń.(<*>)
Operator nie umożliwia takich zakłóceń: Działanie i argumentów obliczenia nie zależy od wartości. To naprawdę gryzie. Porównaćktóry wykorzystuje wynik jakiegoś efektu do wyboru między dwoma obliczeniami (np. wystrzelenie rakiet i podpisanie rozejmu), podczas gdy
która używa wartości
ab
do wyboru między wartościami dwóch obliczeńat
iaf
, po przeprowadzeniu obu, być może z tragicznym skutkiem.Wersja monadyczna polega zasadniczo na dodatkowej mocy
(>>=)
wyboru obliczeń z wartości, a to może być ważne. Jednak wspieranie tej mocy utrudnia komponowanie monad. Jeśli spróbujemy zbudować „podwójne wiązanie”dotarliśmy tak daleko, ale teraz wszystkie nasze warstwy są pomieszane. Mamy
n (m (n t))
, więc musimy pozbyć się zewnętrznegon
. Jak mówi Alexandre C, możemy to zrobić, jeśli mamy odpowiednipermutować do
n
wewnątrz ijoin
do drugiegon
.Słabsze „podwójne zastosowanie” jest znacznie łatwiejsze do zdefiniowania
ponieważ nie ma interferencji między warstwami.
W związku z tym dobrze jest rozpoznać, kiedy naprawdę potrzebujesz dodatkowej mocy
Monad
s i kiedy możesz uciec ze sztywną strukturą obliczeniową, któraApplicative
obsługuje.Zwróć uwagę, że chociaż komponowanie monad jest trudne, może to być więcej niż potrzebujesz. Typ
m (n v)
wskazuje na obliczanie zm
-efektami, a następnie obliczanie zn
-efekty do -wartościv
, gdziem
-efekty kończą się przedn
rozpoczęciem -efekty (stąd potrzebaswap
). Jeśli chcesz po prostu przeplataćm
-efekty zn
-efektami, to o skład może zbyt wiele prosić!źródło
m
in
zawsze można napisać transformator monadamt
, a działają wn (m t)
użyciumt n t
? Czyli zawsze możesz skomponować monady, to jest po prostu bardziej skomplikowane, używając transformatorów?data Free f x = Ret x | Do (f (Free f x))
, więcdata (:+:) f g x = Inl (f x) | Tnr (g x)
i zastanów sięFree (m :+: n)
. To opóźnia wybór sposobu uruchamiania przeplotów.Maybe
ten oznacza, że wczesnaNothing
będzie tłumić ocenya
późniejszego / kolejnegoJust a
. Czy to jest poprawne?Monady zrobić komponować, ale wynik może nie być monada. W przeciwieństwie do tego kompozycja dwóch aplikantów jest z konieczności aplikatywna. Podejrzewam, że intencją pierwotnego stwierdzenia było to, że „Aplikacyjność komponuje, a monadność nie”. Ponownie, „
Applicative
jest zamknięty w kompozycji, aMonad
nie jest”.źródło
Jeśli masz aplikacje
A1
iA2
, to typdata A3 a = A3 (A1 (A2 a))
też jest aplikacyjny (możesz napisać taką instancję w sposób ogólny).Z drugiej strony, jeśli masz monady
M1
iM2
typdata M3 a = M3 (M1 (M2 a))
niekoniecznie jest monadą (nie ma sensownej ogólnej implementacji dla>>=
lubjoin
dla kompozycji).Jednym z przykładów może być typu
[Int -> a]
(tu skomponować konstruktora typu[]
z(->) Int
, z których oba są monady). Możesz łatwo pisaćI to uogólnia na każdą aplikację:
Ale nie ma sensownej definicji
Jeśli nie jesteś tego przekonany, rozważ następujące wyrażenie:
Długość zwracanej listy musi być ustawiona w kamieniu przed podaniem liczby całkowitej, ale prawidłowa jej długość zależy od podanej liczby całkowitej. Dlatego nie
join
może istnieć żadna poprawna funkcja dla tego typu.źródło
IO
bez programuMonad
byłoby bardzo trudne do zaprogramowania. :)Komponowanie monad, http://web.cecs.pdx.edu/~mpj/pubs/RR-1004.pdf
źródło
swap : N M a -> M N a
ContT r m a
nie jest anim (Cont r a)
aniCont r (m a)
, iStateT s m a
jest z grubszaReader s (m (Writer s a))
.swap
implikuje, że kompozycja pozwala jakoś „współpracować”. Zauważ również, żesequence
jest to specjalny przypadek „zamiany” dla niektórych monad. Tak jestflip
w rzeczywistości.swap :: N (M x) -> M (N x)
, wygląda mi na to, że możesz użyćreturns
(odpowiedniofmap
ped), aby wstawićM
z przodu iN
z tyłu, przechodząc odN (M x) -> M (N (M (N x)))
, a następnie użyjjoin
kompozytu, aby uzyskać swójM (N x)
.Rozwiązanie prawa dystrybucji l: MN -> NM jest wystarczające
aby zagwarantować monadyczność NM. Aby to zobaczyć, potrzebujesz jednostki i wielu. skoncentruję się na mnogości (jednostka to jednostka_N jednostka M)
Ten sposób nie gwarantuje, że MN jest monada.
Kluczowa obserwacja pojawia się jednak, gdy masz rozwiązania prawa dystrybucyjnego
zatem LM, LN i MN są monadami. Powstaje pytanie, czy LMN jest monadą (albo wg
(MN) L -> L (MN) lub przez N (LM) -> (LM) N
Mamy wystarczającą strukturę, aby stworzyć te mapy. Jednak, jak zauważa Eugenia Cheng , potrzebujemy warunku heksagonalnego (który sprowadza się do przedstawienia równania Yanga-Baxtera), aby zagwarantować monadyczność obu konstrukcji. W rzeczywistości, przy warunku heksagonalnym, dwie różne monady pokrywają się.
źródło