# Intro Classes for accessing and mutating nested data types with corresponding adapter classes for `MonadState`, `MonadReader` and `MonadError`. Inspired by the [next level mtl with classy optics] talk. [Hackage] # Internals Lenses and Prisms from [lens] are autogenerated with [TH] by splicing with `deepPrisms` and `deepLenses`. The generator recurses into single-field constructors and record fields if there are instances of `DeepPrisms` or `DeepLenses` for their parameter types. # Example For `MonadError`: ```haskell {-# LANGUAGE TemplateHaskell #-} import Cornea (MonadDeepError(throwHoist)) import Control.Monad.Trans.Except (runExceptT) import Data.DeepPrisms (deepPrisms) newtype Error = Error String newtype Inner = Inner Error deepPrisms ''Inner data Mid = Mid Inner deepPrisms ''Mid newtype Outer = Outer Mid deepPrisms ''Outer throwDeep :: MonadDeepError e Inner m => m () throwDeep = throwHoist (Inner (Error "boom")) main :: IO (Either Outer ()) main = runExceptT throwDeep ``` In `main`, `MonadError Outer IO` and `DeepPrisms Outer Inner` are summoned. Analogously for `MonadState`: ```haskell {-# LANGUAGE TemplateHaskell #-} import Cornea (MonadDeepState(get, gets, put)) import Control.Monad.Trans.State (execStateT) import Data.DeepLenses (deepLenses) newtype S = S Int newtype Inner = Inner { _innerS :: S } deepLenses ''Inner data Mid = Mid { _midInner :: Inner } deepLenses ''Mid newtype Outer = Outer { _outerMid :: Mid } deepLenses ''Outer stateDeep :: MonadDeepState s Inner m => m () stateDeep = do (Inner (S a)) <- get b <- gets $ \(Inner (S b)) -> b put (Inner (S (a + b + 3))) main :: IO Outer main = do execStateT stateDeep (Outer (Mid (Inner (S 5)))) ``` `MonadReader` works basically the same as `MonadState`. [lens]: https://hackage.haskell.org/package/lens [TH]: https://hackage.haskell.org/package/template-haskell [next level mtl with classy optics]: https://github.com/gwils/next-level-mtl-with-classy-optics [Hackage]: https://hackage.haskell.org/package/cornea