content: {-# LANGUAGE UndecidableInstances #-}
  
  module Data.Field.Galois.Tower
    ( TowerOfFields(..)
    , (*^)
    ) where
  
  import Protolude
  
  import Data.Field.Galois.Base (GaloisField)
  import Data.Field.Galois.Prime (Prime, fromP)
  import Data.Field.Galois.Extension (Extension, IrreducibleMonic, pattern V)
  import Data.Field.Galois.Binary (Binary, toB')
  
  -------------------------------------------------------------------------------
  -- Types
  -------------------------------------------------------------------------------
  
  -- | Tower of fields @L@ over @K@ strict partial ordering.
  class (GaloisField k, GaloisField l) => TowerOfFields k l where
    {-# MINIMAL embed #-}
    -- | Embed @K@ into @L@ naturally.
    embed :: k -> l
  
  -------------------------------------------------------------------------------
  -- Instances
  -------------------------------------------------------------------------------
  
  -- Prime field towers are reflexive.
  instance KnownNat p => TowerOfFields (Prime p) (Prime p) where
    embed = identity
    {-# INLINABLE embed #-}
  
  -- Extension field towers are reflexive.
  instance IrreducibleMonic p k => TowerOfFields (Extension p k) (Extension p k) where
    embed = identity
    {-# INLINABLE embed #-}
  
  -- Extension fields are towers of fields.
  instance {-# OVERLAPPING #-} IrreducibleMonic p k => TowerOfFields k (Extension p k) where
    embed = V
    {-# INLINABLE embed #-}
  
  -- Extension field towers are transitive.
  instance {-# OVERLAPPABLE #-} (TowerOfFields k l, IrreducibleMonic p l, TowerOfFields l (Extension p l))
    => TowerOfFields k (Extension p l) where
    embed = embed . (embed :: k -> l)
    {-# INLINABLE embed #-}
  
  -- Binary field towers are reflexive.
  instance KnownNat p => TowerOfFields (Binary p) (Binary p) where
    embed = identity
    {-# INLINABLE embed #-}
  
  -- Binary fields are towers of fields.
  instance KnownNat p => TowerOfFields (Prime 2) (Binary p) where
    embed = toB' . fromP
    {-# INLINABLE embed #-}
  
  -------------------------------------------------------------------------------
  -- Functions
  -------------------------------------------------------------------------------
  
  -- | Scalar multiplication.
  infixl 7 *^
  (*^) :: TowerOfFields k l => k -> l -> l
  (*^) = (*) . embed
  {-# INLINE (*^) #-}
  