packages feed

strongweak-0.11.0: src/Strongweak/WeakenN.hs

module Strongweak.WeakenN ( WeakenN(..) ) where

import Strongweak.WeakenN.Internal
import Strongweak.Weaken ( Weaken(..), type WeakenedN )
import Strongweak.Strengthen ( Strengthen(..) )
import GHC.TypeNats ( type Natural )

{- | When weakening (or strengthening), chain the operation @n@ times.

You may achieve this without extra newtypes by nesting uses of
'Strongweak.Weaken.SW'. However, strongweak generics can't handle this, forcing
you to write manual instances.

'WeakenN' provides this nesting behaviour in a type. In return for adding a
boring newtype layer to the strong representation, you can chain weakening and
strengthenings without having to write them manually.

The type works as follows:

@
Weakened (WeakenN 0 a) = a
Weakened (WeakenN 1 a) = Weakened a
Weakened (WeakenN 2 a) = Weakened (Weakened a)
Weakened (WeakenN n a) = WeakenedN n a
@

And so on. (This type is only much use from @n = 2@ onwards.)
-}
newtype WeakenN (n :: Natural) a = WeakenN { unWeakenN :: a }
    deriving stock Show
    deriving (Ord, Eq) via a

instance WeakenWeakenN n a => Weaken (WeakenN n a) where
    type Weakened (WeakenN n a) = WeakenedN n a
    weaken = weakenWeakenN @n @a . unWeakenN

instance StrengthenWeakenN n a => Strengthen (WeakenN n a) where
    strengthen = fmap WeakenN . strengthenWeakenN @n @a