strongweak-0.3.0: src/Strongweak/Generic/Weaken.hs
-- | 'weaken' over generic representations.
module Strongweak.Generic.Weaken where
import Strongweak.Weaken
import GHC.Generics
-- | Weaken a value generically.
--
-- The weak and strong types must be /compatible/. See 'Strongweak.Generic' for
-- the definition of compatibility in this context.
weakenGeneric :: (Generic s, Generic w, GWeaken (Rep s) (Rep w)) => s -> w
weakenGeneric = to . gweaken . from
class GWeaken s w where
gweaken :: s p -> w p
-- | Strip all meta.
instance GWeaken s w => GWeaken (M1 is ms s) (M1 iw mw w) where
gweaken = M1 . gweaken . unM1
-- | Nothing to do for empty datatypes.
instance GWeaken V1 V1 where
gweaken = id
-- | Nothing to do for empty constructors.
instance GWeaken U1 U1 where
gweaken = id
-- | Special case: if source and target types are equal, copy the value through.
instance GWeaken (Rec0 s) (Rec0 s) where
gweaken = id
-- | Weaken a field using the existing 'Weaken' instance.
instance {-# OVERLAPS #-} (Weaken s, Weak s ~ w) => GWeaken (Rec0 s) (Rec0 w) where
gweaken = K1 . weaken . unK1
-- | Weaken product types by weakening left and right.
instance (GWeaken ls lw, GWeaken rs rw) => GWeaken (ls :*: rs) (lw :*: rw) where
gweaken (l :*: r) = gweaken l :*: gweaken r
-- | Weaken sum types by casing and weakening left or right.
instance (GWeaken ls lw, GWeaken rs rw) => GWeaken (ls :+: rs) (lw :+: rw) where
gweaken = \case L1 l -> L1 $ gweaken l
R1 r -> R1 $ gweaken r