Jakie problemy programowe rozwiązują Monady? [Zamknięte]

14

Przeczytałem wiele postów, które wyjaśniają, czym są monady, jak uniti jak binddziałają, niektóre z nich pogrążają się w teorii kategorii tak abstrakcyjnej (przynajmniej dla mnie), że powodują krwawienie oczu, niektóre ignorują to całkowicie i dotykają dziwnych analogii burrito, pudełka i co nie.

Po kilku tygodniach badań i wielu smażonych neuronach (chyba) rozumiem, jak działają Monady. Ale wciąż jest jedna rzecz, która nie pozwala mi zrozumieć, coś, o czym tak naprawdę niewiele postów dotyczy (poza IO i stanem):

DLACZEGO?

Dlaczego monady mają znaczenie? Dlaczego są tak ważne? Jakie problemy rozwiązują? Czy problemy te można rozwiązać tylko za pomocą Monad, czy też istnieją inne sposoby?

Dummy Me
źródło
3
Programy są duże i złożone. Potrzebujemy sposobów ich ustrukturyzowania. Jest wiele sposobów. Monady są jednym. Strzały są jednym. Functors to jeden. Obiekty, klasy, funkcje, metody, moduły, cechy, miksy, pakiety, to jeszcze niektóre, naprawdę nie jest jasne, jakie jest twoje konkretne pytanie. Pytasz, dlaczego potrzebujemy strukturyzować programy?
Jörg W Mittag
1
@ JörgWMittag: NIE pytam, dlaczego potrzebujemy strukturyzować programy. Oczywiście duży problem dzieli się na mniejsze, które można rozwiązać, a następnie połączyć, aby uzyskać rozwiązanie dużego. Pytam, jakie problemy rozwiązują Monady. Czy to to? Kod strukturalny? Czy to tyle zamieszania? Na przykład w Haskell jest to sposób wykonywania operacji we / wy. Tam monada jest sztuką udającą, że zachowuje się jak coś czystego, a tak naprawdę nie jest. Moje pytanie jest w tytule, nie wiem, jak to wyrazić w jaśniejszy sposób.
Dummy Me,
2
Dlaczego monady?
Robert Harvey
1
@RobertHarvey: Znalazłem również dwa pierwsze dodane linki, ale podobnie jak w odpowiedziach na te i inne posty, odpowiedzi idą prosto do monad Może, State i IO, szybko przechodząc do przykładów lub kodu i kończąc na „jest dużo problemów, które można rozwiązać za pomocą Monad ”. Jakie są inne rodzaje problemów? Szukam odpowiedzi na wyższym poziomie, która zamiast powtarzać te same przykłady, faktycznie trafia do źródła problemów (cokolwiek to są) i wyjaśniam, w jaki sposób Monady je rozwiązują i dlaczego jest to najlepszy wybór, zamiast używać czegoś innego. Bardzo dziękuję za opinie.
Dummy Me

Odpowiedzi:

10

Nie potrzebujesz monad, aby cokolwiek rozwiązać. Po prostu upraszczają niektóre rzeczy. Wiele osób jest zbyt abstrakcyjnych i teoretycznych, tłumacząc monady. Przeważnie monady są wzorcem, który pojawia się wielokrotnie w programowaniu. Rozpoznając ten wzorzec, możemy uprościć nasz kod i uniknąć ponownego wprowadzania niektórych funkcji.

Dla Haskell, z konkretnego punktu widzenia, najbardziej widoczną rzeczą, którą monady umożliwiają, jest notacja . Rozumienie list w języku Haskell i innych językach również w dużym stopniu wykorzystuje monady. Możesz także tworzyć biblioteki takie jak Control.Monad .

Wszystkie zapewniają przydatne uproszczenia, a po zaimplementowaniu go dla jednej monady automatycznie otrzymujesz go dla wszystkich monad. Jest to jeden z głównych powodów, dla których ponowne użycie kodu jest o wiele łatwiejsze do programowania funkcjonalnego niż w przypadku innych paradygmatów.

Karl Bielefeldt
źródło
2
Powiedziałbym, że najbardziej widoczną rzeczą, którą włączają monady haskell, jest łatwy sposób na uzyskanie efektów IO, które faktycznie działają tak, jak tego oczekujesz. Myślę, że każdy, kto zastanawia się, co dają nam monady, powinien wypróbować Mirandę . Miranda to język, który Haskell zaprojektowano w celu zastąpienia, i powinien być bardzo łatwy do nauczenia dla każdego, kto ma doświadczenie w Haskell. Główną różnicą jest to, że nie ma monadycznego We / Wy, co sprawia, że ​​praca z językiem jest znacznie trudniejsza niż w przypadku Haskell dla każdego nietrywialnego projektu.
Jules
Tak, IOjest najbardziej znaną monadą Haskella , ale nie wymieniłem przykładów pojedynczych monad. Wymieniłem przykłady nadrzędnych abstrakcji, które umożliwiają. Próbowałem dowiedzieć się, dlaczego na przykład pierwszy facet, który pomyśli o użyciu monady dla IO, uznałby, że ogólnie jest to dobry pomysł.
Karl Bielefeldt
1
@Jules: Lub spójrz na historię Haskell. Przed Monadami projektanci Haskell eksperymentowali z Lazy Strumieniami i Kontynuacjami jako podstawą I / O i oba były trudne w użyciu.
Jörg W Mittag
5

Łatwiej jest zrozumieć, jeśli spojrzysz na poszczególne monady i zobaczysz, jakie problemy rozwiązują. Na przykład w Haskell:

  • IO: Pozwala na reprezentację IO w systemie typów, dzięki czemu można usunąć oddzielne czyste funkcje od funkcji wykonujących IO.

  • Lista: Umożliwia wykonywanie porównań list i obliczeń nodeterministycznych.

  • Może: Lepsza alternatywa dla zer i obsługa czegoś porównywalnego z operatorem zerowania w języku C #.

  • Parsec: Wygodny DSL do pisania parserów.

Łatwo więc (mam nadzieję) zobaczyć uzasadnienie poszczególnych monad, ponieważ wszystkie są całkiem przydatne. Ale problemy, które rozwiązują, są również zupełnie inne i na pierwszy rzut oka nie mają ze sobą wiele wspólnego, z wyjątkiem tego, że wszystkie są związane z pewną logiką operacji łańcuchowych. Monady są przydatne, ponieważ pozwalają budować tak różnorodne narzędzia.

Czy powyższe przykłady można zaimplementować bez monad? Z pewnością można je zaimplementować w sposób ad-hoc, ale posiadanie monad wbudowanych w język pozwala na bezpośrednie wsparcie języka, takie jak doadnotacja, która działa ze wszystkimi monadami.

JacquesB
źródło
2

Jedną z rzeczy, która sprawia, że ​​jest to mylące, jest to, że „popularne” funkcje jak bindi <*>są zorientowane na praktykę. Ale aby zrozumieć pojęcia, łatwiej jest najpierw spojrzeć na inne funkcje. Warto również zauważyć, że monady wyróżniają się, ponieważ są nieco przesadzone w porównaniu do innych powiązanych koncepcji. Zacznę więc od funktorów.

Functors oferują funkcję (w notacji Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b. Innymi słowy, masz kontekst f, w którym możesz podnieść funkcję. Jak możesz sobie wyobrazić, prawie wszystko jest funktorem. Listy, być może, albo funkcje, I / O, krotki, parsery ... Każdy przedstawia kontekst, w którym może pojawić się wartość. Możesz więc pisać niezwykle wszechstronne funkcje, które działają w prawie każdym kontekście, używając fmaplub jego wbudowanego wariantu <$>.

Jakie inne rzeczy chcesz robić z kontekstami? Możesz połączyć dwa konteksty. Więc może chcesz uzyskać uogólnienie zip :: [a] -> [b] -> [(a,b)]na przykład tak: pair :: (Monoidal f) => f a -> f b -> f (a,b).

Ale ponieważ jest to jeszcze bardziej przydatne w praktyce, biblioteki Haskell oferują zamiast tego Applicative, co jest kombinacją Functori Monoidal, A także Unit, co po prostu dodaje, że możesz w rzeczywistości umieścić wartości „wewnątrz” swojego kontekstu unit.

Możesz pisać niezwykle ogólne funkcje, po prostu podając te trzy rzeczy na temat kontekstu, w którym pracujesz.

Monadto po prostu kolejna rzecz, którą można dodać do tego. To, czego wcześniej nie wspomniałem, to to, że masz już dwa sposoby łączenia dwóch kontekstów: możesz nie tylko pairje, ale możesz także układać w stosy, np. Możesz mieć listę list. W kontekście We / Wy przykładem może być akcja We / Wy, która może odczytać inne akcje We / Wy z pliku, więc masz typ FilePath -> IO (IO a). Jak możemy pozbyć się tego stosu, aby uzyskać funkcję wykonywalną IO a? Tam właśnie pojawia się Monads join, pozwala nam połączyć dwa konteksty tego samego typu. To samo dotyczy parserów, może itd. I bindjest po prostu bardziej praktycznym sposobem użyciajoin

Tak więc kontekst monadyczny musi oferować tylko cztery rzeczy i może być używany z prawie wszystkimi maszynami opracowanymi dla I / O, parserów, awarii itp.

MarLinn
źródło
1

Monady pozwalają wyrażać różne nieczyste obliczenia, a także upraszczają kod

  • obliczenia stanowe (get / set state via monad)
  • I / O (logowanie, interfejs użytkownika, plik lub po prostu tworzenie / używanie listy X)
  • Także „nieliniowy” przepływ sterowania (tzn. Może wyjątki itp.)

I, co ważne, bez kompromisów z konstrukcjami czystego języka i uzyskiwania z niego czystszego języka

Macke
źródło
2
To prawda - ale to tylko część tego, do czego służą monady. Wymień Maybepojęcia lub nie są powiązane z niczym zewnętrznym.
JacquesB
Byłoby pomocne, gdyby downvoters wyjaśnił, dlaczego to zrobili. Nie widzę nic złego w tej odpowiedzi.
Jules
@JacquesB są jednak stanowe.
Jules
1
Typy świata, typy wyjątkowości, typy liniowe również to umożliwiają.
Jörg W Mittag
@Jules Lists jako monada niedeterminizmu jest stanowa? Czy możesz wyjaśnić, jaka jest twoja definicja „stanowej”?
Jack