Uma coisa que torna confuso é que o "popular" funciona como bind
e <*>
é orientado para a práxis. Mas, para entender os conceitos, é mais fácil observar outras funções primeiro. Também vale a pena notar que as mônadas se destacam porque são um pouco exageradas em comparação com outros conceitos conectados. Então, vou começar com functors.
Functors oferecem uma função (na notação Haskell) fmap :: (Functor f) => (a -> b) -> f a -> f b
. Em outras palavras, você tem um contexto no f
qual você pode elevar uma função. Como você pode imaginar, quase tudo é um functor. Lista, Talvez, Qualquer um, funções, E / S, tuplas, analisadores ... Cada um representa um contexto no qual um valor pode aparecer. Assim, você pode escrever funções extremamente versáteis que funcionam em praticamente qualquer contexto usando fmap
ou sua variante embutida <$>
.
Que outras coisas você quer fazer com os contextos? Você pode combinar dois contextos. Então você pode querer obter uma generalização zip :: [a] -> [b] -> [(a,b)]
por exemplo como este: pair :: (Monoidal f) => f a -> f b -> f (a,b)
.
Mas, como é ainda mais útil na prática, as bibliotecas Haskell oferecem Applicative
, que é uma combinação de Functor
e Monoidal
, e também deUnit
, o que apenas acrescenta que você pode realmente colocar valores "dentro" do seu contexto unit
.
Você pode escrever funções extremamente genéricas, declarando essas três coisas sobre o contexto em que está trabalhando.
Monad
é apenas mais uma coisa que você pode afirmar além disso. O que eu não mencionei antes é que você já tem duas maneiras de combinar dois contextos: você pode não apenas pair
eles, mas também pode empilhá-los; por exemplo, você pode ter uma lista de listas. No contexto de E / S, um exemplo seria uma ação de E / S que pode ler outras ações de E / S de um arquivo, portanto você teria um tipo FilePath -> IO (IO a)
. Como podemos nos livrar desse empilhamento para obter uma função executável IO a
? É aí que Monad
s join
chega, ele nos permite combinar dois contextos empilhados do mesmo tipo. O mesmo vale para analisadores, talvez etc. Ebind
é apenas uma maneira mais prática de usarjoin
Portanto, um contexto monádico apenas oferece quatro coisas e pode ser usado com quase todo o maquinário desenvolvido para E / S, analisadores, falhas etc.