packages feed

strongweak-0.2.0: src/Strongweak/Generic/Weaken.hs

-- | Weakening for generic data types.

module Strongweak.Generic.Weaken where

import Strongweak.Weaken

import GHC.Generics

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 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 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