{-# LANGUAGE LambdaCase #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} module Main where import Data.Functor.Identity import Data.Monoid.Endo import Data.Monoid.Endo.AnEndo import Data.Default.Class (Default(def)) data Verbosity = Silent | Normal | Verbose | Annoying deriving (Show {- ... -}) instance Default Verbosity where def = Normal class HasVerbosity s where verbosity :: Functor f => (Verbosity -> f Verbosity) -> s -> f s setVerbosity :: HasVerbosity s => Verbosity -> s -> s setVerbosity v = runIdentity . verbosity (const (Identity v)) data Config = Config { cfgVerbosity :: Verbosity -- ... } deriving (Show) instance HasVerbosity Config where verbosity f cfg@Config{cfgVerbosity = v} = (\v' -> cfg{cfgVerbosity = v'}) <$> f v data Action = NormalAction Config | ShowVersion | ShowHelp deriving (Show {- ... -}) instance Default Config where def = Config { cfgVerbosity = def -- ... } instance Default Action where def = NormalAction def instance AnEndo Verbosity where type EndoOperatesOn Verbosity = Action anEndo v = Endo $ \case NormalAction cfg -> NormalAction $ setVerbosity v cfg action -> action