É recomendável que você leia o
primeiro artigo, se ainda não o fez. Este artigo será mais curto, menos focado em detalhes e mais em recursos.
Segundo
Stephen Diel , junto com os tipos dependentes, compilação mais rápida e um limite de entrada mais baixo; efeitos algébricos são uma das tarefas mais importantes que serão resolvidas no futuro para Haskell.
O futuro não está muito longe, então você precisa começar agora.
Aumentando efeitos para outros efeitos
class Liftable eff schema where lift :: eff ~> schema
O que significa "elevação" em essência?
lift é o mesmo
puro /
retorno, com a exceção de que não imergimos o valor no efeito, mas o efeito em algum tipo de transformador (no nosso caso, no circuito do transformador):
pure :: a -> ta lift :: ua -> tua
Isso nos permite usar qualquer efeito dentro de um transformador específico - é fácil introduzir novos efeitos, mas mais tarde precisaremos interpretar cada um deles.
Assim, podemos compor com segurança os efeitos levantados:
let f = lift get :: Configured _ t => t _ let g = lift Nothing :: Optional t => t _ let h = lift (failure _) :: Failable _ t => t _ let x = f *> g *> h :: (Applicative t, Configured _ t, Optional t, Failable _ t) => t _
E envie-os em qualquer ordem conveniente para nós:
let y = pure _ :: Reader _ :> State _ :> Either _ :> Maybe := Int let z = pure _ :: State _ :> Either _ :> Maybe _ :> Reader := _ let x = f *> g *> h :: (Applicative t, Configured _ t, Optional t, Failable _ t) => t _ let xy = x *> y :: Reader _ :> State _ :> Either _ :> Maybe := _ let xz = x *> z :: State _ :> Either _ :> Maybe _ :> Reader := _
Adapte alguns efeitos a outros
class Adaptable subeff eff | subeff -> eff where adapt :: subeff ~> eff
Adaptação significa que alguns efeitos podem ser substituídos por efeitos mais poderosos. Por exemplo, os efeitos do
Reader e
Writer podem ser usados no
State , porque o
State pode ler e gravar e, assim, alterar o valor armazenado:
lift put :: Accumulated _ t => t _ lift get :: Configured _ t => t _ (lift . adapt $ put) :: Stateful _ t => t _ (lift . adapt $ get) :: Stateful _ t => t _
Como isso é possível? No artigo anterior, dividimos
State em dois efeitos:
State s = (->) s :. (,) s
No caso do
Reader , simplesmente elevamos o functor de seta para o nível de
estado e, no caso do
Writer , o functor de tupla:
Reader s = (->) s Writer s = (,) s
Podemos adaptar o
Disponível para
Opcional , mas perderemos as informações de erro:
(lift $ Just _) :: Optional t => t _ (lift $ failure _) :: Failable _ t => t _ (lift . adapt $ failure _) :: Optional t => t _
Executar efeitos em transformadores
Para interpretar um efeito em um transformador, basta um método de
execução :
let xy = x *> y :: Reader _ :> State _ :> Either _ :> Maybe := _ let xy' = run xy _ :: State _ :> Either _ :> Maybe := _ let xy'' = run xy' _ :: Either _ :> Maybe := _ let xy''' = run xy'' :: Maybe (Either _) _
Conclusão e exemplos
Portanto, agora, sem mônadas livres / livres (e às vezes até sem mônadas), usando
joint você pode digitar suas expressões de acordo com os efeitos que elas produzem. Tudo que você precisa é uma composição de functores.
Também há uma
apresentação de um relatório sobre esse tópico no
comício local em Rostov-on-Don, que pode ser visto em um navegador.
Os melhores exemplos são aqueles que estão o mais próximo possível da realidade. Adoro música, para que você possa ver como esse sistema de efeitos é usado em um
programa que baixa álbuns do Bandcamp .