Esta é uma tradução do excelente post feito por Aditya Bhargava. O post original pode ser lido aqui.
Ao traduzir o post realizei algumas escolhas, tais como:
- manter os nomes dos conceitos em inglês, exemplo: Functors(Funtores) e Monads.
- Algumas expressões não fazem sentido se forem traduzidas literalmente para o português, outras perdem o contexto cultural quando você às trás para o Brasil. Por exemplo, Aditya cita Mel Gibson no texto(acredito eu) pelo uso excessivo de álcool. Portanto acredito que um substituto para ele seja Zecá Pagodinho, me processe
Se você encontrar qualquer erro na tradução e você encontrará, não utilizei corretores ortográficos, não se acanhe em enviar um pull request.
A imagem abaixo representa um valor simples
E você sabe como aplicar uma função(ex: adicione +3) cujo o argumento é o valor acima,
Muito simples! Uma generalização para o processo acima é dizer que qualquer valor pode estar dentro de um contexto. Um recurso didático é imaginar que o contexto é uma caixa na qual você pode colocar valores dentro
Agora, quando você aplica uma função a este valor você receberá diferentes resultados dependendo do contexto em que o resultado está inserido. Esta é a ideia que serve de alicerce para Functors, Applicatives, Monads, Arrows(veja morfismos) etc. Em se tratando de contextos, o tipo Maybe define dois contextos
data Maybe a = Nothing | Just aPosteriormente eu lhe mostrarei as diferenças quando se aplica uma função em algo que é um Just ou Nothing, mas antes disso vamos conversar um pouco sobre Functors!
Quando um valor está envolto por um contexto ele não permite a aplicação de uma função "ordinária" à ele
Aqui é onde o fmap surge. O fmap tem consciência do contexto. O fmap sabe como atuar funções em valores
que estão envoltos por um contexto. Por exemplo, suponha que você queira
aplicar (+3) em Just 2. Usando fmap isso é fácil
> fmap (+3) (Just 2)
Just 5Bum! fmap mostra seu valor. Mas como fmap sabe como deve aplicar uma função?
Um Functor é chamado de typelcass. A figura a baixo apresenta a definição
Um functor é qualquer tipo de dado que define como fmap se aplicará a ele. Aqui, como o fmap funciona:
Então podemos fazer o seguinte
> fmap (+3) (Just 2)
Just 5E fmap magicamente aplica isto (Just 2) a função, pois Maybe é um Functor. A imagem abaixo especifica como fmap deve atuar em Just's e Nothing's:
instance Functor Maybe where
fmap func (Just val) = Just (func val)
fmap func Nothing = NothingO que acontece quando escrevemos fmap +(3) (Just 2)
Você gostou? Certo fmap, então aplique (+3) em um Nothing
> fmap (+3) Nothing
Nothing
Bill O’Reilly sendo ignorante sobre Maybe (Não conhecia esse cara até traduzir esse post, não confunda com Tim O'Reilly)
Assim como Morfeu em Matrix fmap sabe o que tem que ser feito. Se você começa com Nothing então ele retorna Nothing. fmap segue o modo zen. Agora faz sentido o porquê da existência do tipo Maybe. Por exemplo, vamos começar a trabalhar com um banco de dados em uma linguagem(nesse caso, ruby) sem Maybe:
post = Post.find_by_id(1)
if post
return post.title
else
return nil
endMas em Haskell:
fmap (getPostTitle) (findPost 1)Se findPost retornar um post, o código acima retornará o título do post através de getPostTitle. Se findPost retornar um Nothing, no final ainda teremos Nothing! Você precisa concordar que isto é uma forma bem mais organizada de trabalhar do que utilizar código em ruby.
No código podemos utilizar <$>, que é uma versão infix de fmap, então comumente você poderá encontrar códigos em haskell escritos da seguinte maneira
getPostTitle <$> (findPost 1)Aqui em baixo segue um outro exemplo: o que acontece quando você aplica uma função em uma lista?
Listas são funtores também! Segue uma definição:
instance Functor [] where
fmap = mapOkay, okay, um último exemplo: o que acontece quando você aplica uma função em outra função?
fmap (+3) (+1)Aqui a função:
Aqui a função aplicada em outra função:
O resultado é outra função!
> import Control.Applicative
> let foo = fmap (+3) (+2)
> foo 10
15Então funcções são funtores também!
instance Functor ((->) r) where
fmap f g = f . gQuando você usa fmap em uma função, você está apenas realizando uma composição de funções!
Applicatives nos levam ao próximo nível. Com um applicative nossos valores são envoltos por contextos assim como Functors
Mas é importante notar que no caso de applicatives nossas funções também são envoltas por contextos!
Applicatives não estão para brincadeira. Control.Applicative define um operador <*>, o qual sabe como aplicar uma função envolta por um contexto em um valor envolto por um contexto
i.e:
> Just (+3) <*> Just 2
Just 5O uso de <*> pode nos retornar situações deveras interessantes. Por exemplo:
> [(*2), (+3)] <*> [1, 2, 3]
[2, 4, 6, 4, 5, 6]Abaixo segue uma coisa que você consegue fazer com Applicatives, mas não consegue fazer com Functors.
Como aplicar uma função que pega dois argumentos para dois valores envoltos em um contexto?
> (+1) <$> (Just 5)
Just (+6)
> Just (+6) <$> (Just 4)
ERRO!!Applicatives:
> Just (+6) <*> (Just 3)
Just 8Applicatives colocam Functors de lado.
"Adultos podem usar funções com qualquer número de argumentos"-Applicative
"Armado com <$> and <*>, eu posso pegar qualquer função que possui qualquer quantidade de argumentos que não estão envoltos por contextos. Então, eu coloco esses argumentos dentro de contextos, e finalmente eu retorno como saída um valor envolto por contexto huehehuuhe!"-Applicative
> (*) <$> Just 5 <*> Just 3
Just 15Ei! Existe uma função chamada liftA2 que faz
a mesma coisa:
> liftA2 (*) (Just 5) (Just 3)
Just 15Como aprender sobre Monads:
- Obtenha um título de Doutor em Ciência da Computação
- Jogue ele fora por que você não precisará dele nesta secção!
Monads estão em alta. Functors aplicam funções a valores dentro de contextos:
Applicative aplicam funções que estão dentro de contextos em valores que por sua vez também estão dentro de outros contextos:
Monads aplicam funções em valores envoltos por contextos e retornam valores envoltos por contextos. A maquinaria das Monads em haskell é representada pela função >>= (“bind”).
Vejamos um exemplo. Good ol’ Maybe is a monad:
Suponha que half é uma função que funciona unicamente com números pares
half x = if even x
then Just (x `div` 2)
else NothingO que acontece se alimentarmos tal função com um valor envolto por um contexto?
Nos precisamos utilizar >>= em nosso valor com contexto para expulsá-lo do contexto, precisamos retirá-lo da caixa.
Aqui uma foto representando >>=
Aqui como ele funciona
> Just 3 >>= half
Nothing
> Just 4 >>= half
Just 2
> Nothing >>= half
NothingMas o que aconteceu dentro da nossa caixa? Monad é um outro typeclass. Segue uma definição parcial de uma Monad
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
Where >>= is:Então uma Maybe Monad é
instance Monad Maybe where
Nothing >>= func = Nothing
Just val >>= func = func valAqui a ação desta monad em Just 3!
E se você passar um Nothing a coisa fica mais simples ainda
Você também pode colocar várias dessas ações em cadeia
> Just 20 >>= half >>= half >>= half
NothingMuito legal! Agora vamos nos mexer um pouco e partir para um outro exemplo: a IO monad
Especifiquemos três funções.
getLinepega os argumentos que são fornecidos por um input do usuário
getLine :: IO StringreadFilepega uma string(que representa o nome do arquivo) e retorna o conteúdo do arquivo cujo nome é essa string
readFile :: FilePath -> IO StringputStrLn :: String -> IO ()Todas essas três funções pegam um valor comum(ou nenhum valor) e retornam um valor dentro de um contexto. Nos podemos encadear todas essas ações utilizando >>=!
getLine >>= readFile >>= putStrLnAw yeah! Acomodem-se em suas cadeiras para o show da Monad! Haskell também nos fornece uma sintaxe sucinta para monads, chamada do notation:
foo = do
filename <- getLine
contents <- readFile filename
putStrLn contents- Functor é um tipo que implementa um Functor typeclass.
- Applicative é um tipo que implementa um Applicative typeclass.
- Monad é um tipo que implementa um Monad typeclass.
- Maybe implenta todos os outros, então é um functor, um applicative e um monad.
Qual é a diferença entre os três?

- functors: você aplica uma função em um valor envolto por um contexto utilizando
fmapou<$> - applicatives: você aplica uma função envolta por um contexto em um valor envolto por um contexto usando
<*>ouliftA - monads: você pega um valor envolto por um contexto, extrai ele, aplica uma função, e retorna um valor envolto por um contexto, para isso você pode usar
>>=ouliftM
Então, querido amigo (Eu penso que neste ponto já posso considerar que somos amigos), eu penso que ambos concordamos que monads são faceis além de serem uma ideia muito inteligente.
Agora que você saboreou esse guia por que não convidar o Zeca Pagodinho para entornar uma cerveja e estudar toda uma secção sobre monads? Tal secção está disponível aqui. Existem muitas coisas que eu passei por cima, pois Miran Lipovaca(criador do Learn You a Haskell) fez um grande trabalho o qual se aprofundanda em monads e muito outros temas, tal trabalho esta disponível gratuitamente neste link : http://learnyouahaskell.com/chapters






























