module HKT.Squash (Squash, squash) where

import Protolude

import HKT.Type (ID)
import GHC.Generics (Generic, Rep, M1(M1), K1(K1), V1, U1, from, to, (:*:)((:*:)), (:+:)(L1, R1))

class Squash a where
    squash :: a Maybe -> Maybe (a ID)
    default squash ::
        ( Generic (a Maybe)
        , Generic (a ID)
        , GSquash (Rep (a Maybe)) (Rep (a ID))
        ) => a Maybe -> Maybe (a ID)
    squash x = to <$> gsquash (from x)

class GSquash a b where
    gsquash :: a p -> Maybe (b p)

instance GSquash a b => GSquash (M1 i c a) (M1 i c b) where
    gsquash (M1 x) = M1 <$> gsquash x
    {-# INLINE gsquash #-}

instance (GSquash a b, GSquash c d) => GSquash (a :*: c) (b :*: d) where
    gsquash (a :*: b) = (:*:) <$> gsquash a <*> gsquash b
    {-# INLINE gsquash #-}

instance (GSquash a b, GSquash c d) => GSquash (a :+: c) (b :+: d) where
    gsquash (L1 x) = L1 <$> gsquash x
    gsquash (R1 x) = R1 <$> gsquash x
    {-# INLINE gsquash #-}

instance GSquash (K1 a (Maybe k)) (K1 a k) where
    gsquash (K1 k) = K1 <$> k
    {-# INLINE gsquash #-}

instance GSquash U1 U1 where
    gsquash U1 = Just U1
    {-# INLINE gsquash #-}

instance GSquash V1 V1 where
    gsquash = (\case {})
    {-# INLINE gsquash #-}