{-# LANGUAGE CPP #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
module Data.Patch.Class where
import Data.Functor.Identity
import Data.Kind (Type)
import Data.Maybe
import Data.Semigroup
( Sum (..)
, Product (..)
#if !MIN_VERSION_base(4,11,0)
, Semigroup(..)
#endif
)
import Data.Proxy
class Patch p where
type PatchTarget p :: Type
apply :: p -> PatchTarget p -> Maybe (PatchTarget p)
applyAlways :: Patch p => p -> PatchTarget p -> PatchTarget p
applyAlways p t = fromMaybe t $ apply p t
instance Patch (Identity a) where
type PatchTarget (Identity a) = a
apply (Identity a) _ = Just a
instance forall (a :: Type). Patch (Proxy a) where
type PatchTarget (Proxy a) = a
apply ~Proxy _ = Nothing
instance (Num a, Eq a) => Patch (Sum a) where
type PatchTarget (Sum a) = a
apply (Sum a) b = if a == 0 then Nothing else Just $ a + b
instance (Num a, Eq a) => Patch (Product a) where
type PatchTarget (Product a) = a
apply (Product a) b = if a == 1 then Nothing else Just $ a * b
composePatchFunctions :: (Patch p, Semigroup p) => (PatchTarget p -> p) -> (PatchTarget p -> p) -> PatchTarget p -> p
composePatchFunctions g f a =
let fp = f a
in g (applyAlways fp a) <> fp