Last active
July 27, 2020 13:41
-
-
Save coproduto/4e7730f1b7f4c8fa93b6b6a85f94eaab to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- `Cont r a` é o tipo de uma computação que produz um `a` e, quando completa, | |
-- irá produzir um `r`. Você pode ver como uma linha de produção com uma parte | |
-- "faltando" - essa parte é a função `a -> r` que o `Cont` precisa para estar | |
-- "completo". | |
newtype Cont r a = Cont { runCont :: (a -> r) -> r } | |
-- pode não ser imediatamente óbvio por que uma função do tipo `(a -> r) -> r` | |
-- precisa, em geral, produzir um `a` internamente - por parametricidade, só existem | |
-- duas formas de uma função polimórfica do tipo `(a -> r) -> r` existir: | |
-- ela precisa "conter" em si própria um `a` e passar esse `a` para a continuação | |
-- dada, | |
-- ou ela precisa "conter" em si própria um `r` e ignorar a continuação dada. | |
instance Functor (Cont r) where | |
fmap f c = Cont $ \rest -> runCont c (rest . f) | |
-- a computação `rest . f` pode ser vista como compondo a função `a -> b` com | |
-- a nova continuação `b -> r` passada, de forma a produzir a função `a -> r` | |
-- necessária para a computação original. | |
instance Applicative (Cont r) where | |
-- para qualquer `a`, podemos produzir uma computação que retorna um | |
-- `r` quando passada uma função que recebe um `a`: | |
-- essa computação simplesmente aplica a função passada ao `a` que ela | |
-- "contém". Isso pode ajudar a deixar mais claro por que `Cont` é um | |
-- `Functor`: (Quase) todo `Cont c` "contém" um `a` que só pode ser extraído | |
-- passando uma função para `runCont c`. | |
pure x = Cont ($ x) | |
-- dado que temos uma computação que precisa de um `(a -> b) -> r` | |
-- e que temos uma computação que precisa de um `a -> r` | |
-- podemos produzir uma computação que precisa de um `b -> r`: | |
cf <*> cx = Cont $ \rest -> | |
runCont cf $ \f -> | |
runCont cx (rest . f) | |
-- para isso, quando a continuação `b -> r` for passada, "produzimos" | |
-- a função `a -> b` contida em `cf` e usamos ela para criar uma função | |
-- `a -> r` assim como na instância de `Functor`. | |
instance Monad (Cont r) where | |
-- dado que temos uma computação que precisa de um `a -> r` | |
-- dado que temos uma computação que, dada um `a`, | |
-- produz uma nova computação que precisa de um `b -> r` (ou seja, | |
-- internamente produz um `b`), | |
-- podemos produzir uma computação que precisa de um `b -> r` (equivalente | |
-- a extrair o `a` da computação original e usar ele para produzir a nova | |
-- computação) | |
cx >>= f = Cont $ \rest -> | |
runCont cx $ \x -> | |
runCont (f x) rest |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment