{-# LANGUAGE 
    ScopedTypeVariables,
    TemplateHaskell,
    TypeFamilies,
    GADTs,
    KindSignatures,
    DataKinds,
    PolyKinds,
    TypeOperators,
    FlexibleContexts,
    RankNTypes,
    UndecidableInstances,
    FlexibleInstances,
    InstanceSigs,
    DefaultSignatures
 #-}
module FirstField (firstField) where

import Generics.SOP
import Data.Promotion.TH
import Data.Promotion.Prelude

promote [d|mapHead xs = map head xs|]

firstOfProduct :: NP I xs -> I (Head xs)
firstOfProduct (I x :* _) = I x

firstOfEach :: NS (NP I) xss -> NS I (MapHead xss)
firstOfEach (Z xs) = Z (firstOfProduct xs)
firstOfEach (S xs) = S (firstOfEach xs)

class AllEqual (xs :: [*]) where
  type AllEqualTo xs :: *
  reduce :: NS I xs -> AllEqualTo xs

instance {-# OVERLAPS #-} AllEqual '[a] where
  type AllEqualTo '[a] = a
  reduce (Z (I x)) = x

instance (AllEqual as, AllEqualTo as ~ a) => AllEqual (a ': as) where
  type AllEqualTo (a ': as) = a
  reduce (Z (I x)) = x
  reduce (S x) = reduce x

firstField :: (Generic a, AllEqual (MapHead (Code a))) => a -> AllEqualTo (MapHead (Code a))
firstField = reduce . firstOfEach . unSOP . from