bowtie-0.8.0: src/Bowtie/Anno.hs
{-# LANGUAGE DeriveAnyClass #-}
module Bowtie.Anno
( Anno (..)
, annoUnit
, annoUnitM
, annoCounit
, annoCounitM
, annoLeft
, annoLeftM
, annoRight
, annoRightM
)
where
import Data.Hashable (Hashable)
import GHC.Generics (Generic)
import Control.Comonad (Comonad (..))
import Control.Exception (Exception)
import Control.Monad.Reader (Reader, ReaderT (..), runReader)
import Data.Bifoldable (Bifoldable (..))
import Data.Bifunctor (Bifunctor (..))
import Data.Bitraversable (Bitraversable (..))
import Data.Functor.Apply (Apply (..))
import Data.Functor.Identity (Identity (..))
import Data.Kind (Type)
import Data.String (IsString (..))
import Data.Typeable (Typeable)
import Prettyprinter (Pretty (..))
-- | An "annotation" with associated value.
type Anno :: Type -> Type -> Type
data Anno k v = Anno {annoKey :: !k, annoVal :: !v}
deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable, Generic)
deriving anyclass (Hashable)
instance Bifunctor Anno where
bimap f g (Anno k v) = Anno (f k) (g v)
instance Bifoldable Anno where
bifoldr f g z (Anno k v) = f k (g v z)
instance Bitraversable Anno where
bitraverse f g (Anno k v) = liftA2 Anno (f k) (g v)
instance (Semigroup k) => Apply (Anno k) where
liftF2 f (Anno k1 v1) (Anno k2 v2) = Anno (k1 <> k2) (f v1 v2)
instance (Monoid k) => Applicative (Anno k) where
pure = Anno mempty
liftA2 = liftF2
instance Comonad (Anno k) where
extract (Anno _ v) = v
duplicate an@(Anno k _) = Anno k an
extend f an@(Anno k _) = Anno k (f an)
instance (Pretty v) => Pretty (Anno k v) where
pretty = pretty . annoVal
instance (Monoid k, IsString v) => IsString (Anno k v) where
fromString = Anno mempty . fromString
instance (Show k, Typeable k, Exception v) => Exception (Anno k v)
-- | 'unit' from 'Adjunction'
annoUnit :: v -> Reader k (Anno k v)
annoUnit v = ReaderT (Identity . (`Anno` v))
annoUnitM :: (Applicative m) => v -> ReaderT k m (Anno k v)
annoUnitM v = ReaderT (pure . (`Anno` v))
-- | 'counit' from 'Adjunction'
annoCounit :: Anno k (Reader k v) -> v
annoCounit (Anno k m) = runReader m k
annoCounitM :: Anno k (ReaderT k m v) -> m v
annoCounitM (Anno k m) = runReaderT m k
-- | 'leftAdjunct' from 'Adjunction'
annoLeft :: (Anno k v -> x) -> v -> Reader k x
annoLeft f v = ReaderT (Identity . f . (`Anno` v))
annoLeftM :: (Anno k v -> m x) -> v -> ReaderT k m x
annoLeftM f v = ReaderT (f . (`Anno` v))
-- | 'rightAdjunct' from 'Adjunction'
annoRight :: (v -> Reader k x) -> Anno k v -> x
annoRight f (Anno k v) = runReader (f v) k
annoRightM :: (v -> ReaderT k m x) -> Anno k v -> m x
annoRightM f (Anno k v) = runReaderT (f v) k