Tentando compor o não compostável: elevar tudo

É 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 .

Source: https://habr.com/ru/post/pt485518/


All Articles