{-# 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')
class (GaloisField k, GaloisField l) => TowerOfFields k l where
{-# MINIMAL embed #-}
embed :: k -> l
instance KnownNat p => TowerOfFields (Prime p) (Prime p) where
embed = identity
{-# INLINABLE embed #-}
instance IrreducibleMonic p k => TowerOfFields (Extension p k) (Extension p k) where
embed = identity
{-# INLINABLE embed #-}
instance {-# OVERLAPPING #-} IrreducibleMonic p k => TowerOfFields k (Extension p k) where
embed = V
{-# INLINABLE embed #-}
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 #-}
instance KnownNat p => TowerOfFields (Binary p) (Binary p) where
embed = identity
{-# INLINABLE embed #-}
instance KnownNat p => TowerOfFields (Prime 2) (Binary p) where
embed = toB' . fromP
{-# INLINABLE embed #-}
infixl 7 *^
(*^) :: TowerOfFields k l => k -> l -> l
(*^) = (*) . embed
{-# INLINE (*^) #-}