Skip to content

Instantly share code, notes, and snippets.

@coproduto
Last active July 27, 2020 13:41
Show Gist options
  • Save coproduto/4e7730f1b7f4c8fa93b6b6a85f94eaab to your computer and use it in GitHub Desktop.
Save coproduto/4e7730f1b7f4c8fa93b6b6a85f94eaab to your computer and use it in GitHub Desktop.
-- `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