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 .