Intentando componer lo no composable: elevar todo

Se recomienda que lea el primer artículo si aún no lo ha hecho. Este artículo será más corto, menos enfocado en detalles y más en capacidades.

Según Stephen Diel , junto con los tipos dependientes, una compilación más rápida y un umbral de entrada más bajo; Los efectos algebraicos son una de las tareas más importantes que Haskell resolverá en el futuro.

El futuro no está lejos, por lo que debe comenzar ahora.

Elevar efectos a otros efectos


class Liftable eff schema where lift :: eff ~> schema 

¿Qué significa "elevación" en esencia? lift es el mismo puro / retorno, con la excepción de que no sumergimos el valor en el efecto, sino el efecto en algún tipo de transformador (en nuestro caso, en el circuito del transformador):

 pure :: a -> ta lift :: ua -> tua 

Esto nos permite usar cualquier efecto dentro de un transformador específico: es fácil introducir nuevos efectos, pero luego tendremos que interpretar cada uno de ellos.

Por lo tanto, podemos componer de forma segura los efectos aumentados:

 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 _ 

Y envíelos en cualquier orden conveniente para nosotros:

 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 := _ 

Adaptar algunos efectos a otros.


 class Adaptable subeff eff | subeff -> eff where adapt :: subeff ~> eff 

La adaptación significa que algunos efectos pueden ser reemplazados por efectos más potentes. Por ejemplo, los efectos de Reader y Writer se pueden usar en State , porque State puede leer y escribir, y así cambiar el valor almacenado:

 lift put :: Accumulated _ t => t _ lift get :: Configured _ t => t _ (lift . adapt $ put) :: Stateful _ t => t _ (lift . adapt $ get) :: Stateful _ t => t _ 

¿Cómo es esto posible? En el artículo anterior, dividimos el Estado en dos efectos:

 State s = (->) s :. (,) s 

En el caso de Reader , simplemente elevamos el functor de flecha al nivel de estado , y en el caso de Writer , el functor de tupla:

 Reader s = (->) s Writer s = (,) s 

Podemos adaptar Failable a Opcional , pero perderemos la información del error:

 (lift $ Just _) :: Optional t => t _ (lift $ failure _) :: Failable _ t => t _ (lift . adapt $ failure _) :: Optional t => t _ 

Ejecutar efectos en transformadores


Para interpretar un efecto en un transformador, un método de ejecución es suficiente:

 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 _) _ 

Conclusión y ejemplos


Entonces, en este momento, sin mónadas libres / libres (y a veces incluso sin mónadas), usando joint puede escribir sus expresiones según los efectos que producen. Todo lo que necesitas es una composición de functors.

También hay una presentación de un informe sobre este tema en el mitin local en Rostov-on-Don, que se puede ver en un navegador.

Los mejores ejemplos son aquellos que están lo más cerca posible de la realidad. Me encanta la música, así que puedes ver cómo se usa este sistema de efectos en un programa que descarga álbumes de Bandcamp .

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


All Articles