Skip to content

tek/cornea

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

41 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

{-# 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:

{-# 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.

About

classy optical monadic state

Topics

Resources

Stars

Watchers

Forks

Packages