packages feed

data-layer-1.0: src/Data/Layer/Coat.hs

{-# LANGUAGE UndecidableInstances #-}

module Data.Layer.Coat where

import Prelude
import Control.Lens
import Control.Monad
import Data.Layer


-- === Coat ===

newtype Coat a = Coat a deriving (Show, Functor, Foldable, Traversable)
type instance Unlayered (Coat a) = a

type family Uncoated a where Uncoated (Coat a) = a
                             Uncoated a        = Uncoated (Unlayered a)

-- Instances

instance Layered   (Coat a)
instance Rewrapped (Coat a) (Coat a')
instance Wrapped   (Coat a) where
    type Unwrapped (Coat a) = a
    _Wrapped' = iso (\(Coat a) -> a) Coat



-- === Coated ===

-- pure interface

class Coated a where coated :: Lens' a (Uncoated a)
instance {-# OVERLAPPABLE #-} ( Layered a
                              , Coated (Unlayered a)
                              , Uncoated a ~ Uncoated (Unlayered a)
                              ) => Coated a        where coated = layered . coated
instance {-# OVERLAPPABLE #-}      Coated (Coat a) where coated = _Wrapped'

uncoat :: Coated a => a -> Uncoated a
uncoat = view coated


-- monadic interface

class CoatedM m a where viewCoatedM :: a -> m (Uncoated a)
                        setCoatedM  :: Uncoated a -> a -> m a

instance {-# OVERLAPPABLE #-} ( Monad m
                              , LayeredM m a
                              , CoatedM m (Unlayered a)
                              , Uncoated a ~ Uncoated (Unlayered a)
                              )       => CoatedM m a        where viewCoatedM = viewLayeredM >=> viewCoatedM
                                                                  setCoatedM  = withLayeredM . setCoatedM
instance {-# OVERLAPPABLE #-} Monad m => CoatedM m (Coat a) where viewCoatedM   = return . uncoat
                                                                  setCoatedM  v = return . set coated v


-- === Coat generator ===

class CoatGen m a where genCoat :: Uncoated a -> m a
instance {-# OVERLAPPABLE #-} ( Monad m
                              , Uncoated (Unlayered a) ~ Uncoated a
                              , CoatGen m (Unlayered a)
                              , LayerGen m a
                              )       => CoatGen m a        where genCoat = genCoat >=> genLayer
instance {-# OVERLAPPABLE #-} Monad m => CoatGen m (Coat a) where genCoat = return . Coat


--class Destruction m a where destroy :: a -> m (Uncoated a)
--instance {-# OVERLAPPABLE #-} Monad m => Destruction m (Coat a) where destroy = return . unlayer
--instance {-# OVERLAPPABLE #-} Monad m => Destruction m (Coat a) where destroy = return . unlayer

--type family Deconstructed a
--class Construction   m a where construct   :: Deconstructed a -> m a
--class Deconstruction m a where deconstruct :: a               -> m (Deconstructed a)